Bind to a custom property with Nancy - c#

I have a class with this property:
public string FeatureString { get; set; }
However I receive this in my JSON:
"feature_string":"someText"
The names do not match, due to the underscore, and thus this property is not being bound.
Giving it an attribute:
[JsonProperty(PropertyName = "feature_string")]
Doesn't seem to help.
Is there, and if there is how, a way to bind with Nancy to a property with a name that differs from the JSON?
Thanks.

I do not think this is supported out of the box.
Two options I can think of:
Build a dedicated request DTO with the structure the request actually has. Nancy can also bind to private inner classes. Your module could contain the feature_string as a field. Field binding is also supported by Nancy. When you data-bound the inner request class, you can map to your real object, e.g. using Automapper. You still need an object having the same structure as the JSON, but at least you can hide it a bit that way.
https://gist.github.com/thecodejunkie/5521941 here is a dynamic model binder which allows binding an incoming JSON to a dynamic. Again using Automapper, you could bind from the dynamic object to your actual object, which should work without explicit configuration. For the feature_string, you could define one explicit mapping rule.

Related

Object to Object Mapping

I have a RESTful service which returns JSON that I am deserialising into classes in c#.
I need to map some of the properties from the deserialised object model into properties in a different class.
However, I would like to do this through an (xml?) config file which can specify the from/to property names, so that mappings can be changed without recompiling code.
For example:
objectA.Name.FirstName = objectB.FirstName
objectA.Name.LastName = objectB.LastName
What is the best way to do this?
You could let something like AutoMapper do the mapping for you.
There are samples in the source code and configuration options in the wiki.
If you want it to to be based on late binding you can use reflection to dynamically execute the property assignments based on xml definitions.
You can see some examples in this asnwer: Set object property using reflection

ServiceStack and JSV: When I serialize a Dictionary<string, object> the type of 'object' is lost on deserialization

In a POCO object, that I persiste using OrmLite, I have the following property:
....
public Dictionary<string, object> CustomData { get; set; }
...
This property is filled with data, like:
customData.Add("_GooglePassword", "blabla"); // this is a String
customData.Add("_ServerPort", 8093); // this is an Int32
// etc...
It is saved in the database as JSV, like this:
{_GooglePassword:blabla,_ServerPort:8093}
The problem comes when I deserialize this, back to the Dictionary in C#, then it puts everything back as strings, as this exception in VS shows:
So, instead of getting it back to an Int32 as it is defined in the class, I get strings, which will give be problems. Im pretty sure that using normal JSON and the DataContract-approach would not have this issue, as I use JSON in other parts.
Am I missing something here?
Thanks =)
Some interesting viewpoints of why inheritance in DTOs is a bad idea from ss author and here.
If your settings can be splitted in profiles, I would suggest you to split in interfaces /classes each cluster of properties and store them in separated strongly-typed properties.
Depending on your context, if you are just storing information and you are not processing or applying business rules to those settings you might receive the dynamic json in a property and storing it as a string. This way you don't create a Settings class just for storing purpose.

Posting a collection of subclasses

I have a requirement for users to edit a list of quotes for a lead, the quotes can be different types such as:
QuoteForProductTypeA
QuoteForProductTypeB
All quote types share a common base class, such as QuoteBase.
I have my quotes displaying fine on the front end, and appear to post back the correct data too.
However, on the server it doesn't obviously doesn't know which subclass to use, so just uses the base class.
I think i need some kind of custom model binder for WebApi to check for a hidden field such as ModelType which contains the type of the object in the collection, the model binder then creates a new object of this type and binds the properties from my posted values to this object.
However, i am stuck at this point with very little documentation / blogs on how to do this.
I have checked the source code for WebApi to see if i can extend a default model binder, but any defaults are sealed classes.
I can only implement IModelBinder by the looks of it, i can create the correct model type by looking for a value called ModelType, but then i'm not sure how to fill the rest of the values in my subclasses, if there was a default model binder i was inheriting from i would just call the base classes bind method.
If your post collection comes from request body, it won't go through model binder. Web API will use formatter to deserialize the content.
If you just want to support json, it's quite easy. Just add following code to your web api config:
config.Formatters.JsonFormatter.SerializerSettings.TypeNameHandling = Newtonsoft.Json.TypeNameHandling.Auto;
The setting will let json.net to save type name in the payload if the runtime type is different with the declare type. When you post it back, json.net will deserialize the payload to the type you specified in the payload.
A sample payload looks like:
{"$type":"MvcApplication2.Models.Car, MvcApplication2","SeatCount":10,"WheelCount":4,"Model":0,"Brand":null}]

How to add MetaData to a dynamically build MVC3 ViewModel?

One of the key features of a project I'm working on is the ability for the user to configure Forms (as in "Forms" to fill-up) based on a pool of pre-existing field types (well known types, for instance "user name", "date of birth" etc. but also "generic types" like "string", "DateTime" etc.).
We used to have a static ViewModel that worked fine for the "well known" types and looked like this:
public class UserInputModel
{
[StringLength(200)]
public string Name { get; set; }
[Required(ErrorMessageResourceName = "BirthDateEmptyError", ErrorMessageResourceType = typeof(Resources.ErrorMessages))]
public DateTime BirthDate { get; set; }
//Here comes a lot of other properties
}
All the known properties were listed and we were showing or hiding them given the context.
But the last requirement came and changed all that. The user shall now be able to add as many generic type fields as he wants. In order to do this, we decided to make this InputModel entirely dynamic. It now looks like this:
public class UserInputModel
{
// Each ModelProperty has an "Id" and a "Value" property
public ICollection<ModelProperty> Properties { get; set; }
}
This works like a charm. The razor view only has to iterates over the collection, create the corresponding controls for each property of the collection in a more than standard way:
#Html.TextBoxFor(m => m.Properties[index].Value);
... and we nicely get the data back as a filled form.
=> This works fine, but we don't have any client-side validation. For this, we would need some Metadata... which we don't have via annotations anymore since we're dynamically creating the model.
In order to provide those MetaData, I created a CustomModelMetadataProvider that inherits from DataAnnotationsModelMetadataProvider and registered it as the new ModelMetadataProvider in the Global.asax. The CreateMetadata() function gets called upon creation of the ViewModel, and that for each of the properties of my ViewModel... sofar so good.
Where the problem starts: in order to add some metadata to the current property, I first need to identify which property I am currently looking at ("Name" has a maxlength of 200, "date of birth" hasn't so I cannot assign a maxlength to every property per default). And somewhow I didn't manage to do that yet since all the properties have the same name Value and the same container type ModelProperty.
I tried accessing the container of the property via reflection, but since the ModelAccessor's target is the ViewModel itself (because of the lambda expression m => m.Properties), the following construct gives me the ViewModel as a whole, not just the ModelProperty:
var container = modelAccessor.Target.GetType().GetField("container");
var containerObject = (UserInputModel)container.GetValue(modelAccessor.Target);
I've been flipping this over and over but cannot find a way to identify which ModelProperty I have in hand. Is there a way to do this?
Update: after flipping this in every possible direction for a while, we finally went another way. We are basically using unobstrusive javascript to use MVC's validation capabilities without touching attributes nor metadata. In short, we add HTML attributes like value-data="true" (and all other required attributes) to the #Html.TextBoxFor() statements. This works wonderfully for all the atomic validations (required, stringlength etc.).
Tim, you can leverage what appears to be client-side validation through Ajax with the Remote attribute on your properties.
Basically, you'll need to set up a validation controller and then write some smarts into that controller. But at least you'd be able to write some helper methods and keep it all in one place. You would have a series of validators, based on the meta data that you are presenting to the end users, and each validator method would work for a particular type with good re-use.
The one pitfall to this approach would be that you would need to write a validation method for each type and condition that you want to support. Sounds like you're having to go down that road anyways, though.
Hope this helps.
See if this article help you: Technique for carrying metadata to View Models with AutoMapper.
Also use this one for ideas (custom model metadata provider): changing viewmodel's MetadataType attribute at runtime
Fluent validation is probably the best option for you in my mind, but its obviously up to you to select the best match among those above.
Update
Try use ModelMetadata and override ModelMetadataProvider: Dive Deep Into MVC: ModelMetadata and ModelMetadataProvider. This way you completely customize your model metadata (this replaces data annotations) and you have complete control on what is happening, rather than relying on ASP.NET MVC.
Another good place to look at it is Creating your own ModelMetadataProvider to handle custom attributes.
Hope this all is of help to you.

ASP.NET MVC model binding - different names for JSON property and C# model properties

I've annotated the properties of my model classes as below.
[DataMember(Name = "EN")]
public string EmployeeName{ get; set; }
This overall results in a compact JSON (I'm serializing using JSON.NET serializer).
However when JSON containing these smaller names is passed using a POST or a PUT request to the controllers, ASP.NET MVC model binding is not able to correctly map the "EN" JSON property to EmployeeName. It expects EmployeeName in JSON.
Any thoughts on how to fix this?
You can't do that out-of-the box. You have two ways of solving this: either renaming properties in your viewmodel (after all, it is a view model, so it has to cope with your restrictions) or you can try writing your own ModelBinder which will take DataMember annotations into consideration when binding properties.

Categories