JSON.NET Abstract / Derived Class Deserialization with WebAPI 2

Viewed 15750

I'm implementing a Web API 2 service that uses JSON.NET for serialization.

When I try to PUT ( deseralize ) updated json data, the abstract class is not present meaning it didn't know what to do with it so it did nothing. I also tried making the class NOT abstract and just inheriting from it and then each PUT deseralized to the base class rather than the derrived class missing the properties of the derrived class.

Example:

public class People
{
      // other attributes removed for demonstration simplicity

      public List<Person> People { get;set; }
}

public abstract class Person
{
      public string Id {get;set;}
      public string Name {get;set;}
}

public class Employee : Person 
{
      public string Badge {get;set;}
}

public class Customer : Person
{
     public string VendorCategory {get;set;}
}

with my web api configured to do typename handling:

public static void Register(HttpConfiguration config)
{
     config.Formatters.JsonFormatter.SerializerSettings.TypeNameHandling = 
            TypeNameHandling.Objects;
}

then I PUT the JSON like:

{
     people: [{
          name: "Larry",
          id: "123",
          badge: "12345",
          $type: "API.Models.Employee, API"
     }]
}

to the web api method:

public HttpResponseMessage Put(string id, [FromBody]People value)
{
      people.Update(value); // MongoDB Repository method ( not important here )
      return Request.CreateResponse(HttpStatusCode.OK);
}

but the output when inspecting value is always:

People == { People: [] }

or if non-abstract:

People == { People: [{ Name: "Larry", Id: "123" }] }

missing the inherrited property. Anyone ran into this problem and come up with anything?

5 Answers

I have tried your scenario now and it works fine. But I did notice that you are missing a , (comma) after the id property in your json input.

I figured this out by using the following ModelState validity check in my action which then showed the error in my request payload. This could be useful to you too:

if (!ModelState.IsValid)
{
    return Request.CreateErrorResponse(HttpStatusCode.BadRequest, this.ModelState);
}

JsonSubTypes library allows specifying which subclass of the given class should be used to deserialize into via attributes just like Jackson library in Java does. To be more specific, you can:

  • Choose a field and specify its value for each subclass, or
  • Specify fields present only in certain subclass.
Related