How to parse a Breeze SaveBundle - breeze

I'm using breeze with EF and doing server side validation in the ContextProvider in BeforeSaveEntity and BeforeSaveEntities. That's working but I'm looking for a way to do this validation at a higher level, preferably before the request hits the controller.
I already have a custom http module where all requests are going through. I'm doing some logging and authentication in the custom http module. My goal is to also add some authorization validation at the same time/place.
Let's say I have a user that is updating his profile record. I have his identity in my auth cookie/token. The profile ID (Database PK) is embedded in the JSON passed in the request body. I can't assume the user didn't maliciously change this profile ID value to another value on the client before sending. So I want to pluck out this ID and validate that it is the ID for this user.
I'm getting the request input stream as a JSON string in my http module. In this string is all the breeze stuff: entities array, entity aspects, and of course, the ID I'm looking for.
Are there any helper utilities that can assist me in parsing this json string? either by pulling out specific values based on entity and property name? Or even reconstructing the objects contained in the bundle?
Thanks

Took a look at the breeze SaveChanges code. It uses a public class called SaveWorkState which is constructed using two arguments: a ContextProvider and a JArray. The content of the JArray is the "entities" property in the JSON sent to the server during the savechanges.
Once the SaveWorkState is constructed you can access the EntityInfo objects via the EntityInfoGroups property.
Here's the relevant code:
var serializerSettings = BreezeConfig.Instance.GetJsonSerializerSettings();
var jsonSerializer = JsonSerializer.Create(serializerSettings);
var saveBundle = ... JObject constructed from the JSON posted to your controller ...;
var dynSaveBundle = (dynamic)saveBundle;
var entitiesArray = (JArray)dynSaveBundle.entities;
var contextProvider = ... EFContextProvider<> ...;
var saveWorkState = new SaveWorkState(contextProvider, entitiesArray);
var entityInfoGroups = saveWorkState.EntityInfoGroups; // <- this is what you want.

Related

breeze-client - any way to consume metadata from Web API?

Hi I created a method on my Web API Controller that successfully returns the metadata as string. I am just wondering if there is a clever way of generating entities at runtime instead of generating entities in TS client side beforehand?
[HttpGet]
public string Metadata()
{
return this.dataContext.Metadata();
}
The point of generating the TypeScript entities beforehand is so that you have types and intellisense to help you write your code correctly.
But of course the EntityManager can create entities on the fly from the metadata; you just need to know the name of the EntityType:
let cust = manager.createEntity("Customer");
And you can query entities from the server without pre-generated classes:
const query = new EntityQuery('Customers').where('lastName', 'startsWith', 'C');
manager.executeQuery(query).then(qr => {
let customers = qr.results;
// do something with customers...
});
In the early days of Breeze, we always loaded the metadata from the server on-the-fly, usually as the app was starting up.
These days, I code in TypeScript, and I find it very helpful to have the metadata and classes pre-generated.
Figured it out. The above method is needed or at least one called Metadata of type HTTP GET. the data service in breeze-client needs to have the property hasServerMetadata to false and the magic happens.

UI5 Can we create json model using just the entity type metadata from a service model

I want to create a model and set it as one of the global model in oninit method of component. I have a sap gateway odata service with just an entity type and do NOT have corresponding entityset.
My ui5 project has manifest.json with default model and component.js Is it possible to to create a model using just the metadata.
When you initialize the model, all you need is the metadata for initializing the SAPUI5 OData model. As long as the metadata is syntactically valid it should not be a problem. The EntitySets are only required when you assign an aggregation to a control using this model.
Update:
Its possible to get the details of the metadata from the model & create a new JSON model with it.
var oModel = new sap.ui.model.odata.ODataModel("http://services.odata.org/V2/OData/OData.svc");
var metaModel = oModel.getMetaModel();
var oEntitySet = metaModel.getODataEntitySet("Products"); //For getting properties of an Entity Set
//For Entity, you may have to provide the service namespace along, in this case ODataDemo
var oEntity = metaModel.getODataEntityType("ODataDemo.Product");
The oEntity object will look something like this
With this you can create a new JSON model as
var oODataJSONModel = new sap.ui.model.json.JSONModel({"Selection" : oEntity.property });
Here is a working example

Signalr 2.0 user and session data

i have a MVC application that contains an ASPX page that will be called in single sign on mode.
How can i set the user that is passed by a request call?
I tried to use "Identity" with no fortune.
example:
string username = "MyUsername";
string userid = Guid.NewGuid().ToString("N"); //could be a constant
List<Claim> claims = new List<Claim>{
new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name", username),
new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier", userid)};
var genericIdentity = new GenericIdentity(username);
genericIdentity.AddClaims(claims);
var genericPrincipal = new GenericPrincipal(genericIdentity, new string[] { "aaa" });
Context.User = genericPrincipal;
The second problem is that i have some data regarding the user but i can't set to session (like expected by signalr design).
How can solve it?
Update:
After some search i understand what i really need. When the page is called i check validation of user on database and if it's verified i need to store this information in a way that is reachable everywhere. It's what i would have done with SESSION object.
For me a user is not a simple string, but it's a complex object that contains useful information for the behaviour of the program.
I hope i am clearer.
You can add state on the client proxy.
If your data is too complex for that, you need to pass it at apprpriate times using hub methods.

Encrypt data passed in View Model

I have a simple post method in a MVC controller that checks whether the ModelState is valid then calls another method passing an instance of the model as a paramter. This model contains sensitive data that is easily obtained by looking at Fiddler. My goal is to somehow mask or encrypt this data so that it cannot be seen in an http trace.
I have seen posts suggesting to use Session or Temp variables but that is not an option in my case.
This is what the code looks like:
[HttpPost]
[ActionName("Search")]
[AccessControl(Xri)]
public ActionResult SearchPost(string string1, ViewModel model)
{
model.NoResults = false;
if (ModelState.IsValid)
{
if (ModelState.IsValid) return RedirectToAction("TargetAction", model);
}
}
[AccessControl(Xri)]
public ActionResult TargetAction(string arg, ViewModel viewModel)
{
.
.
.
}
Fiddler shows the following:
/TargetAction?id=01010101&date=08%2F14%2F2013%2000%3A00%3A00&To=08%2F21%2F2013%2000%3A00%3A00&param1=somevalue&param2=somevalue2
Is there a way to mask the url parameters shown here?
You're going to need to get SSL running on your server.
Without a server certificate from a trusted authority, there is very little you can do to encrypt the data over the wire. Why? Because you'd need to send encryption/decryption details in clear text before you start sending the data so that your client (likely JavaScript) could decode it.
Using a certificate and operating on 443 gives you built-in functionality from the server/browser that is hard to beat in a custom implementation.
If you just want to obscure the data (and put it beyond the level of most web users) you could always base64 encode the data, rather than encrypting it. Just be clear that you are NOT encrypting data and it is still possible to decode it. This approach is not a form of encryption.
If you decide to take that approach regardless, here are a few resources:
Client-side Encoding/Decoding
MSDN Reference on Encoding to Base64
Cheers.
You have two options for doing this:
Store the data on the server and give the user a token (e.g. a GUID) to pass along to retrieve the data. Since using the Session or TempData is not an option, you could store the viewmodel in the database, and then redirect the user with the token in the URL to retrieve it on the next request.
The other option would be to have the user pass the viewmodel in the URL as you're currently doing, but pass it in an encrypted format. For example, you could
serialize the model to JSON, encrypt it using one of .NET's built in encryption algorithms, and then redirect to the next action passing the encrypted string as your view model. Then you could change the target action to something like:
[AccessControl(Xri)]
public ActionResult TargetAction(string arg, string encryptedViewModel)
{
var decryptedString = Decrypt(encryptedViewModel) ; // supply the decrypt function to match your encryption
var viewModel = JsonConvert.DeserializeObject(decryptedString);
}

what is the best way to store a user filtered query params in a database table?

I have an ASP.NET MVC website. In my backend I have a table called People with the following columns:
ID
Name
Age
Location
... (a number of other cols)
I have a generic web page that uses model binding to query this data. Here is my controller action:
public ActionResult GetData(FilterParams filterParams)
{
return View(_dataAccess.Retrieve(filterParams.Name, filterParams.Age, filterParams.location, . . .)
}
which maps onto something like this:
http://www.mysite.com/MyController/GetData?Name=Bill .. .
The dataAccess layer simply checks each parameter to see if its populated to add to the db where clause. This works great.
I now want to be able to store a user's filtered queries and I am trying to figure out the best way to store a specific filter. As some of the filters only have one param in the queryString while others have 10+ fields in the filter I can't figure out the most elegant way to storing this query "filter info" into my database.
Options I can think of are:
Have a complete replicate of the table (with some extra cols) but call it PeopleFilterQueries and populate in each record a FilterName and put the value of the filter in each of field (Name, etc)
Store a table with just FilterName and a string where I store the actual querystring Name=Bill&Location=NewYork. This way I won't have to keep adding new columns if the filters change or grow.
What is the best practice for this situation?
If the purpose is to save a list of recently used filters, I would serialise the complete FilterParams object into an XML field/column after the model binding has occurred. By saving it into a XML field you're also giving yourself the flexibility to use XQuery and DML should the need arise at a later date for more performance focused querying of the information.
public ActionResult GetData(FilterParams filterParams)
{
// Peform action to get the information from your data access layer here
var someData = _dataAccess.Retrieve(filterParams.Name, filterParams.Age, filterParams.location, . . .);
// Save the search that was used to retrieve later here
_dataAccess.SaveFilter(filterParams);
return View(someData);
}
And then in your DataAccess Class you'll want to have two Methods, one for saving and one for retrieving the filters:
public void SaveFilter(FilterParams filterParams){
var ser = new System.Xml.Serialization.XmlSerializer(typeof(FilterParams));
using (var stream = new StringWriter())
{
// serialise to the stream
ser.Serialize(stream, filterParams);
}
//Add new database entry here, with a serialised string created from the FilterParams obj
someDBClass.SaveFilterToDB(stream.ToString());
}
Then when you want to retrieve a saved filter, perhaps by Id:
public FilterParams GetFilter(int filterId){
//Get the XML blob from your database as a string
string filter = someDBClass.GetFilterAsString(filterId);
var ser = new System.Xml.Serialization.XmlSerializer(typeof(FilterParams));
using (var sr = new StringReader(filterParams))
{
return (FilterParams)ser.Deserialize(sr);
}
}
Remember that your FilterParams class must have a default (i.e. parameterless) constructor, and you can use the [XmlIgnore] attribute to prevent properties from being serialised into the database should you wish.
public class FilterParams{
public string Name {get;set;}
public string Age {get;set;}
[XmlIgnore]
public string PropertyYouDontWantToSerialise {get;set;}
}
Note: The SaveFilter returns Void and there is no error handling for brevity.
Rather than storing the querystring, I would serialize the FilterParams object as JSON/XML and store the result in your database.
Here's a JSON Serializer I regularly use:
using System.IO;
using System.Runtime.Serialization.Json;
using System.Text;
namespace Fabrik.Abstractions.Serialization
{
public class JsonSerializer : ISerializer<string>
{
public string Serialize<TObject>(TObject #object) {
var dc = new DataContractJsonSerializer(typeof(TObject));
using (var ms = new MemoryStream())
{
dc.WriteObject(ms, #object);
return Encoding.UTF8.GetString(ms.ToArray());
}
}
public TObject Deserialize<TObject>(string serialized) {
var dc = new DataContractJsonSerializer(typeof(TObject));
using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(serialized)))
{
return (TObject)dc.ReadObject(ms);
}
}
}
}
You can then deserialize the object and pass it your data access code as per your example above.
You didn't mention about exact purpose of storing the filter.
If you insist to save filter into a database table, I would have following structure of the table.
FilterId
Field
FieldValue
An example table might be
FilterId Field FieldValue
1 Name Tom
1 Age 24
1 Location IL
3 Name Mike
...
The answer is much more simple than you are making it:
Essentially you should store the raw query in its own table and relate it to your People table. Don't bother storing individual filter options.
Decide on a value to store (2 options)
Store the URL Query String
This id be beneficial if you like open API-style apps, and want something you can pass nicely back and forth from the client to the server and re-use without transformation.
Serialize the Filter object as a string
This is a really nice approach if your purpose for storing these filters remains entirely server side, and you would like to keep the data closer to a class object.
Relate your People table to your Query Filters Table:
The best strategy here depends on what your intention and performance needs are. Some suggestions below:
Simple filtering (ex. 2-3 filters, 3-4 options each)
Use Many-To-Many because the number of combinations suggests that the same filter combos will be used lots of times by lots of people.
Complex filtering
Use One-To-Many as there are so many possible individual queries, it less likely they are to be reused often enough to make the extra-normalization and performance hit worth your while.
There are certainly other options but they would depend on more detailed nuances of your application. The suggestions above would work nicely if you are say, trying to keep track of "recent queries" for a user, or "user favorite" filtering options...
Personal opinion
Without knowing much more about your app, I would say (1) store the query string, and (2) use OTM related tables... if and when your app shows a need for further performance profiling or issues with refactoring filter params, then come back... but chances are, it wont.
GL.
In my opinion the best way to save the "Filter" is to have some kind of json text string with each of the "columns names"
So you will have something in the db like
Table Filters
FilterId = 5 ; FilterParams = {'age' : '>18' , ...
Json will provide a lot of capabilities, like the use of age as an array to have more than one filter to the same "column", etc.
Also json is some kind of standard, so you can use this "filters" with other db some day or to just "display" the filter or edit it in a web form. If you save the Query you will be attached to it.
Well, hope it helps!
Assuming that a nosql/object database such as Berkeley DB is out of the question, I would definitely go with option 1. Sooner or later you'll find the following requirements or others coming up:
Allow people to save their filters, label, tag, search and share them via bookmarks, tweets or whatever.
Change what a parameter means or what it does, which will require you to version your filters for backward compatibility.
Provide auto-complete functions over filters, possibly using a user's filter history to inform the auto-complete.
The above will be somewhat harder to satisfy if you do any kind of binary/string serialization where you'll need to parse the result and then process them.
If you can use a NoSql DB, then you'll get all the benefits of a sql store plus be able to model the 'arbitrary number of key/value pairs' very well.
Have thought about using Profiles. This is a build in mechanism to store user specific info. From your description of your problem its seems a fit.
Profiles In ASP.NET 2.0
I have to admit that M$ implementation is a bit dated but there is essentially nothing wrong with the approach. If you wanted to roll your own, there's quite a bit of good thinking in their API.

Resources