0

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!

Community
  • 1
  • 1
Céryl Wiltink
  • 1,879
  • 11
  • 13
  • Forgot to mention, I cannot touch the models as they are external to the Api-project, so using the ModelBinder attribute on the Person-Poco is not possible, the logic for binding has to stay in the Web Api project, if at all possible. – Céryl Wiltink Jul 01 '15 at 13:33
  • How do you think about Dto classes? then in the controller you convert them to model objects somehow, eg using automapper. – hazjack Jul 01 '15 at 15:38
  • what i would do is create a single address model and have everything specific to ConcreteAddressType1 and ConcreteAddressType2 in it. so when a post data comes in they will be assigned to what ever fields are there and then based on the data you can decide how to map it. does that make sense. – Prashant Jul 01 '15 at 16:30

0 Answers0