views:

12609

answers:

3

I have a complex JSON object which is sent to the View without any issues (as shown below) but I cannot work out how Serialize this data back to a .NET object when it is passed back to the controller through an AJAX call. Details of the various parts are below.

   var ObjectA = {
        "Name": 1,
        "Starting": new Date(1221644506800),

        "Timeline": [
            {
                "StartTime": new Date(1221644506800),
                "GoesFor": 200

            }
            ,
            {
                "StartTime": new Date(1221644506800),
                "GoesFor": 100

            }

        ]
    };

I am not sure how this object can be passed to a Controller Method, I have this method below where the Timelines object mirrors the above JS object using Properties.

public JsonResult Save(Timelines person)

The jQuery I am using is:

        var encoded = $.toJSON(SessionSchedule);

        $.ajax({
            url: "/Timeline/Save",
            type: "POST",
            dataType: 'json',
            data: encoded,
            contentType: "application/json; charset=utf-8",
            beforeSend: function() { $("#saveStatus").html("Saving").show(); },
            success: function(result) {
                alert(result.Result);
                $("#saveStatus").html(result.Result).show();
            }
        });

I have seen this question which is similar, but not quite the same as I am not using a forms to manipulate the data. http://stackoverflow.com/questions/267707/how-to-pass-complex-type-using-json-to-asp-net-mvc-controller

I have also seen references to using a 'JsonFilter' to manually deserialize the JSON, but was wondering if there is a way to do it nativly though ASP.NET MVC? Or what are the best practices for passing data in this way?

+7  A: 

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

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

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

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

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

public ActionResult Save(FormCollection forms) {
  string json = forms[0];
  // do your thing here.
}
swilliams
+21  A: 

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 can then apply it to your controller methods like so:

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

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

DaRKoN_
Nice answer, not sure why this wasn't the accepted one, certainly helped me out...
JonoW
I am using this method to implement the same thing, but for some reason I am getting an exception on the ReadObject method: "Expecting element 'root' from namespace ''.. Encountered 'None' with name '', namespace ''." Any ideas why?
Dan Appleyard
This answer helped me out too. Thanks.
PulsarBlow