[ACCEPTED]-ASP.NET MVC How to pass JSON object from View to Controller as Parameter-json

Accepted answer
Score: 54

Edit:

This method should no longer be needed with 7 the arrival of MVC 3, as it will be handled 6 automatically - http://weblogs.asp.net/scottgu/archive/2010/07/27/introducing-asp-net-mvc-3-preview-1.aspx


You can use this ObjectFilter:

    public class ObjectFilter : ActionFilterAttribute {

    public string Param { get; set; }
    public Type RootType { get; set; }

    public override void OnActionExecuting(ActionExecutingContext filterContext) {
        if ((filterContext.HttpContext.Request.ContentType ?? string.Empty).Contains("application/json")) {
            object o =
            new DataContractJsonSerializer(RootType).ReadObject(filterContext.HttpContext.Request.InputStream);
            filterContext.ActionParameters[Param] = o;
        }

    }
}

You 5 can then apply it to your controller methods 4 like so:

    [ObjectFilter(Param = "postdata", RootType = typeof(ObjectToSerializeTo))]
    public JsonResult ControllerMethod(ObjectToSerializeTo postdata) { ... }

So basically, if the content type 3 of the post is "application/json" this 2 will spring into action and will map the 1 values to the object of type you specify.

Score: 13

You say "I am not using a forms to 14 manipulate the data." But you are doing 13 a POST. Therefore, you are, in fact, using 12 a form, even if it's empty.

$.ajax's dataType tells 11 jQuery what type the server will return, not what 10 you are passing. POST can only pass a form. jQuery 9 will convert data to key/value pairs and pass it as a query string. From the 8 docs:

Data to be sent to the server. It is converted 7 to a query string, if not already a string. It's 6 appended to the url for GET-requests. See 5 processData option to prevent this automatic processing. Object 4 must be Key/Value pairs. If value is an 3 Array, jQuery serializes multiple values 2 with same key i.e. {foo:["bar1", "bar2"]} becomes 1 '&foo=bar1&foo=bar2'.

Therefore:

  1. You aren't passing JSON to the server. You're passing JSON to jQuery.
  2. Model binding happens in the same way it happens in any other case.
Score: 11

A different take with a simple jQuery plugin

Even though answers to this question are 23 long overdue, but I'm still posting a nice 22 solution that I came with some time ago 21 and makes it really simple to send complex JSON to Asp.net MVC controller 20 actions so they are model bound to whatever 19 strong type parameters.

This plugin supports dates just 18 as well, so they get converted to their 17 DateTime counterpart without a problem.

You can find 16 all the details in my blog post where I examine the 15 problem and provide code necessary to accomplish 14 this.

All you have to do is to use this plugin 13 on the client side. An Ajax request would 12 look like this:

$.ajax({
    type: "POST",
    url: "SomeURL",
    data: $.toDictionary(yourComplexJSONobject),
    success: function() { ... },
    error: function() { ... }
});

But this is just part of 11 the whole problem. Now we are able to post 10 complex JSON back to server, but since it 9 will be model bound to a complex type that 8 may have validation attributes on properties 7 things may fail at that point. I've got 6 a solution for it as well. My solution takes advantage of jQuery 5 Ajax functionality where results can be 4 successful or erroneous (just as shown in 3 the upper code). So when validation would 2 fail, error function would get called as it's 1 supposed to be.

Score: 4

There is the JavaScriptSerializer class you can use too. That 9 will let you deserialize the json to a .NET 8 object. There's a generic Deserialize<T>, though you will 7 need the .NET object to have a similar signature 6 as the javascript one. Additionally there 5 is also a DeserializeObject method that just makes a plain 4 object. You can then use reflection to get at 3 the properties you need.

If your controller 2 takes a FormCollection, and you didn't add anything else 1 to the data the json should be in form[0]:

public ActionResult Save(FormCollection forms) {
  string json = forms[0];
  // do your thing here.
}
Score: 2

This answer is a follow up to DaRKoN_'s 15 answer that utilized the object filter:

[ObjectFilter(Param = "postdata", RootType = typeof(ObjectToSerializeTo))]
    public JsonResult ControllerMethod(ObjectToSerializeTo postdata) { ... }

I 14 was having a problem figuring out how to 13 send multiple parameters to an action method 12 and have one of them be the json object 11 and the other be a plain string. I'm new 10 to MVC and I had just forgotten that I already 9 solved this problem with non-ajaxed views.

What 8 I would do if I needed, say, two different 7 objects on a view. I would create a ViewModel 6 class. So say I needed the person object 5 and the address object, I would do the following:

public class SomeViewModel()
{
     public Person Person { get; set; }
     public Address Address { get; set; }
}

Then 4 I would bind the view to SomeViewModel. You 3 can do the same thing with JSON.

[ObjectFilter(Param = "jsonViewModel", RootType = typeof(JsonViewModel))] // Don't forget to add the object filter class in DaRKoN_'s answer.
public JsonResult doJsonStuff(JsonViewModel jsonViewModel)
{
     Person p = jsonViewModel.Person;
     Address a = jsonViewModel.Address;
     // Do stuff
     jsonViewModel.Person = p;
     jsonViewModel.Address = a;
     return Json(jsonViewModel);
}

Then in 2 the view you can use a simple call with 1 JQuery like this:

var json = { 
    Person: { Name: "John Doe", Sex: "Male", Age: 23 }, 
    Address: { Street: "123 fk st.", City: "Redmond", State: "Washington" }
};

$.ajax({
     url: 'home/doJsonStuff',
     type: 'POST',
     contentType: 'application/json',
     dataType: 'json',
     data: JSON.stringify(json), //You'll need to reference json2.js
     success: function (response)
     {
          var person = response.Person;
          var address = response.Address;
     }
});
Score: 1

in response to Dan's comment above:

I am 11 using this method to implement the same 10 thing, but for some reason I am getting 9 an exception on the ReadObject method: "Expecting 8 element 'root' from namespace ''.. Encountered 'None' with 7 name '', namespace ''." Any ideas 6 why? – Dan Appleyard Apr 6 '10 at 17:57

I 5 had the same problem (MVC 3 build 3.0.11209.0), and 4 the post below solved it for me. Basically 3 the json serializer is trying to read a 2 stream which is not at the beginning, so 1 repositioning the stream to 0 'fixed' it...

http://nali.org/asp-net-mvc-expecting-element-root-from-namespace-encountered-none-with-name-namespace/

More Related questions