6

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.

abatishchev
  • 98,240
  • 88
  • 296
  • 433
Paul Hinett
  • 1,951
  • 2
  • 26
  • 40

1 Answers1

10

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}]
Hongye Sun
  • 3,868
  • 1
  • 25
  • 18
  • Thank you, that done the trick. I was serializing my model to json for knockoutJs to consume with this code: Html.Raw(Json.Encode(Model)), however i had to swap out this code to use the Json.Net serializer instead, and specify the TypeNameHandling option there too...just in case others are looking for the answer. – Paul Hinett Oct 14 '12 at 22:41
  • 1
    In case it's helpful to anyone else - `$type` must be the first field listed in the object or JSON.Net won't be able to deserialize it. – Daniel Schilling Jul 31 '14 at 20:20