I'm currently having a problem that I cannot seem to find an answer for. In my web api 2 project, we use the post request to add a resource to the database. However, during serialization of the JSON to Model, i'm running into a problem with some of the models properties that are actually abstract. Let me illustrate:
Classes
public class Person
{
public string Name {get; set;}
public virtual Address Address {get; set;}
}
public abstract class Address
{
public int Id {get; set;}
}
public class ConcreteAddressType1 : Address
{
public string Street {get; set;}
}
public class ConcreteAddressType2 : Address
{
public string POBox {get; set;}
}
The ApiController Action looks like this:
[HttpPost]
public async Task<IHttpActionResult> Post([FromBody]Person person)
{
// Validate and save to Database
return person;
}
Currently out-of-the-box this property Address is always null, which makes sense, since it is abstract an must be either one of the two concrete instances which the serializer cannot decide on its own. So when deserializing the request body to an instance of Person, I need to "somehow" check the Address-field of the passed in Json/XML and depending on that, decide which concrete class it has to be. The fields for the two Address-superclasses are different enough that I can decide which concrete class it has to be.
So I have tried making custom model binders, for both the Person and Address, but it doesn't feel good, I just want to know if there is a way to use the regular Web Api ModelBinder for Person which works perfectly, just use a different custom binder for one of its properties.
I found something in JSON.NET Abstract / Derived Class Deserialization with WebAPI 2, however, I need a solution without the client $type parameter. I also found Web Api Model Binding and Polymorphic Inheritence which looks really close to how I see it, but this is for the entire class in the parameter, not one of it's properties.
Lastly, I found I can do something like this with a custom model binder:
[HttpPost]
public async Task<IHttpActionResult> Post([FromBody]Person person, [ModelBinder(typeof(AdresModelBinder))]Address address)
{
//The custom modelbinder has bound address to the correct concrete class
person.Address = address
// Validate and save to Database
return person;
}
But I'd like to just have the one input parameter and the entire Person object for readability reasons and separate binding and combining seems error-prone and not in the Controller-actions's scope.
Thanks!