Reputation: 1138
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!
Upvotes: 0
Views: 1729
Reputation: 7748
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.
Upvotes: 1