Search code examples
asp.net-mvcserializationknockout.jsasp.net-web-apiknockout-mapping-plugin

WebAPI deserializing a knockout mapping null string as "null"


I have an ASP.NET MVC 4 project that retrieves data and injects it into my client-side ViewModel using ko.mapping so that it can be bound in knockoutJS:

$(document).ready(function () {
    // Get the data from the server-side
    var koModel = new MessageModel( [JSON-string] );
    // Inject server-side model into the client-side viewModel
    var viewModel = new MessageViewModel(koModel);
    // Bind knockout
    ko.applyBindings(viewModel);
});

// model loaded from the server-side
var MessageModel = function (data) {
    var self = this;
    ko.mapping.fromJS(data, {}, self);
}
// client-side data-bound viewModel
var MessageViewModel = function(koModel) {
    var self = this;
    self.data = koModel;

    // Submit form
    self.sendMessage = function () {
        $.ajax({
            url: 'http://services.mysite.net/api/Messaging',
            type: 'POST',
            data: self.data
        });
    }
}

One of those properties is a string. And the JSON correctly looks like this:

"MyProperty": null

However, when I POST to a WebAPI 2.0 service, the Request parameter looks like this:

"MyProperty": "null"

And when WebAPI receives it deserializes that string as as "null" instead of null.

    [HttpPut]
    async public Task<IHttpActionResult> 
        Put(int id, [FromBody]MessageModel model)
    {
        // model.MyProperty is now "null" instead of being a null value

Solution

  • Since you're working with JSON, you should use ko.mapping.fromJSON() instead of ko.mapping.fromJS() (see "Working with JSON strings" in documentation). And in your ajax call, you should use the opposite conversion method: ko.mapping.toJSON():

    ...
    data: ko.mapping.toJSON(self);
    ...
    

    See this simple demo. I've created a simple Web API project to verify this, works like a charm.