Ajax Post a Knockout Stringified Json Object to an ASP.NET MVC5 Controller

Typically there isn’t a simple way to post from JavaScript a Json object as a string and receive it as such in a controller. This is because the model binding system interferes in the background and when it sees a Json-like string attempts to bind it to a model, but if you have not specified a model in your controller function parameter then it turns it into a null even if you specified that you wanted a string. Thanks model binder, you suck.

So the way around it is to create a wrapper model that contains a string into which you can dump your stringified Json object like this:

Public Class JsonViewModel
    Property Json As String = ""
End Class

Here’s the controller with the function that takes the model as a parameter:

 <HttpPost>
Function Save(model As JsonViewModel) As ActionResult
    If model IsNot Nothing AndAlso model.Json.Length > 0 Then
        Debug.Print(model.Json.ToString)
        'TODO: Process data, either of the following ways will work but the second is more obvious
        'Dim json = JsonConvert.DeserializeObject(model.Json)
        'For Each item In json
        ' Debug.Print(item.Name & ": " & item.Value)
        'Next
        Dim dictjson = JsonConvert.DeserializeObject(Of Dictionary(Of String, Object))(model.Json)
        For Each kvp As KeyValuePair(Of String, Object) In dictjson
            Debug.Print(kvp.Key & ": " & kvp.Value.ToString)
        Next
        Return New HttpStatusCodeResult(200)
    Else
        Return New HttpStatusCodeResult(500)
    End If
End Function

Here’s the JavaScript from inside a Knockout ViewModel that posts the stringified Json object:

self.Save = function () {
    var payload = ko.toJSON(self);
    $.ajax("/Home/Save/", {
        type: "POST",
        processData: false,
        contentType: "application/json; charset=utf-8",
        data: JSON.stringify({ Json: payload })
    })
    .done(function (data) {
        alert('Data saved');
    })
    .fail(function () {
        alert('Data not saved.');
    });
};