2

In my last SO question, I asked how to modify the serializer settings for Json.NET, which ASP.NET Web API natively uses for (de)serialization. The accepted answer worked perfectly, and I was, for example, able to embed type information into the serialized JSON string.

However, when I try to throw back this JSON string to a Web API action that's expecting the model's parent class, Web API still deserializes to the parent class, removes all data corresponding to the child class, and prevents casting to and detection of the child class.

class Entity { }
class Person : Entity { }

public Person Get() {
    return new Person();
}

public bool Post(Entity entity) {
    return entity is Person;
}

A simple use case would be doing something like this in jQuery:

// get a serialized JSON Person
$.ajax({
    url : 'api/person'      // PersonController
}).success(function (m) {

    // then throw that Person right back via HTTP POST
    $.ajax({
        url : 'api/person',
        type : 'POST',
        data : m
    }).success(function (m) {
        console.log(m);     // false
    });

})

I'd expect that by modifying the JsonSerializerSettings of Json.NET to embed type information that it'd be able to read that and at the very least, try to force deserialization to that type, but apparently it does not.

How should I tackle something like this?

Community
  • 1
  • 1
Richard Neil Ilagan
  • 14,627
  • 5
  • 48
  • 66

2 Answers2

1

Web API really doesn't do any (de)serialization "natively". It happens to have a few MediaTypeFormatters included in the config.Formatters collection by default. Feel free to remove those and create your own MediaTypeFormatter that handles the serialization the way you want it to be done.

MediaTypeFormatters are really not that hard to create.

Darrel Miller
  • 139,164
  • 32
  • 194
  • 243
  • Yeah, I did consider having to roll out a custom `MediaTypeFormatter` to handle the task, but thought of it as a last resort. I was thinking that since Web API used Json.NET by default anyway, that there might be something to tweak / toggle that does the above, but obviously it's not as easy as that. – Richard Neil Ilagan Nov 09 '12 at 15:31
1

Actually the 2nd POST call is sending application/x-www-form-urlencoded data and that's why the type information is not picking up by the JsonMediaTypeFormatter. Try setting the contentType to be "application/json".

Also, the data in the 2nd POST request body seems to be encoded and it needs to be decoded before sending back to the service.

I was able to get this to work:

    // get a serialized JSON Person
    $.ajax({
        url: 'api/person'      // PersonController
    }).success(function (m) {

        // then throw that Person right back via HTTP POST
        $.ajax({
            url: 'api/person',
            type: 'POST',
            contentType: "application/json",
            data: JSON.stringify(m),
        }).success(function (m) {
            alert(m);     // true!
        });

    })
Maggie Ying
  • 10,095
  • 2
  • 33
  • 36
  • Cool, great catch. :D Wired this up, and yeah, the data is coming in as a `Person`, but as an instance of `Entity` still. It can now be cast to `Person` (e.g. `entity as Person !== null` now), but it's still missing that one key step to automatically get a `Person` in. I may have to take the information in your answer and slap that with Darrel's answer on custom `MediaTypeFormatter`s. :-/ Much appreciated though! – Richard Neil Ilagan Nov 09 '12 at 17:14