0

I'm having problems when I try to deserialize json into a object in MVC4.

I have a Viewmodel:

 public class TestViewModel
{
    public string Code { get; set; }

}

On the view I get the model and serialize the object using Json.net

var Vm = function(data) {
        var self = this;

        ko.mapping.fromJS(data, {}, self);

        self.GetResults = function() {
            $.ajax({
                type: "POST",
                url: '@Url.Action("Action", "Controller")',
                data: ko.mapping.toJSON(self),
                success: function(data) {
                    alert('OK');
                }
            });
        };
    };

    var viewModel = new Vm(@Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model)));
    ko.applyBindings(viewModel);

My problem is when I call GetResults the action in the controller, all properties are null.

My Json is:

{"Code":"TestCode"}

I have the same structure in a MVC3 project and works fine. I'm missing something in MVC4?

Cheers!

2
  • Have you tried using Fiddler to see what the request and response look like? Commented Jan 14, 2013 at 22:27
  • Yes, the request looks fine, it has Content-Type: application/json Accept: application/json, text/javascript, /; q=0.01, and the json in the question {"Code":"TestCode"} Commented Jan 14, 2013 at 22:32

1 Answer 1

1

We've noticed that in some scenarios jQuery will embed the data in a Form in the Request. When this happens, the values are not automatically mapped to the object type in the Controller method.

To get around this, you need to do two things:

1) Check to see if the data is serialized. I found an easy way to do this and dumped it in an extension method:

public static class WebContextExtensions
{
    public static bool IsDataSerialized(this HttpContext context)
    {
        return context.Request.Params.AllKeys[0] == null;
    }
}

2) IF IsDataSerialized returns true, you need to deserialize the data into your object type. We wrote a GenericDeserializer method to do that as well:

public class GenericContextDeserializer<T> where T : new()
{
    public T DeserializeToType(HttpContext context)
    {
        T result = new T();
        if (context != null)
        {
            try
            {
                string jsonString = context.Request.Form.GetValues(0)[0].ToString();
                Newtonsoft.Json.JsonSerializer js = new Newtonsoft.Json.JsonSerializer();
                result = js.Deserialize<T>(new Newtonsoft.Json.JsonTextReader(
                               new System.IO.StringReader(jsonString)));
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        else
            throw new NullReferenceException();
        return result;
    }
}

Now put it all together in your Controller method:

[HttpPost]
[HttpOptions]
public HttpResponseMessage MyAction(JsonData data)
{
    var results = Request.CreateResponse();
    try
    {
        data = new GenericContextDeserializer<JsonData>().DeserializeToType(HttpContext.Current);
        // do stuff with data
        results.StatusCode = HttpStatusCode.OK;
    }
    catch (Exception ex)
    {
        results.StatusCode = HttpStatusCode.InternalServerError;
    }
    return results;
}

If you want more detail, it's in the second half of a blog post I wrote.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.