Passing JSON into an ASP.NET MVC Controller

It is easy to pass JSON from the controller class to the View in MVC, just do something like the following:

public JsonResult Claim(int? videoId)
{

return Json("ok");

}

It is also easy enough to pass parameters into the controller via jquery or javascript or just a url.  Here is a Jquery call that passes a customer id back to the controller.

$.ajax({

type: "POST",

url: "/Products/AddCustomer",

data: "customerId=" + val,

success: function(msg) {

alert("Data Saved: " + msg);

}

});

But if you try to pass a JSON object to MVC it falls apart:

object customer = new Object();

customer.Name = "fred";

customer.Location = "Virginia";

$.ajax({

type: "POST",

contentType: "application/json; charset=utf-8",

url: "/Products/GetCustomer",

data: $.toJSON(customer),

success: ShowGrid,

error:

function(XMLHttpRequest, textStatus, errorThrown) {

//execute code related to failier of web service

}

});

}

The JSON object will never reach the controller.  the reason is that an MVC controller method has no idea on its end what to expect.

A guy named Omar Al Zabir came up with a sweet solution for handling this:

1)  Create an attribute that overrides the OnActionExecuting event handler.

2) Interecept the JSON object from inside the stream

3) use attribute parameters to figure out the type of object you want to stream the data into.

4)  deserialize the JSON object into your object.

It works like a charm!  Here is the ObjectFilter class that defines the attribute:

using System;

using System.Collections.Generic;

using System.IO;

using System.Linq;

// you'll need to include System.ServiceModel.Web in your references
// to get the Json namespace included in your project

using System.Runtime.Serialization.Json;

using System.Web;

using System.Web.Mvc;

using System.Web.Mvc.Ajax;

using System.Xml.Linq;

using System.Xml.Serialization;

using FilmmakerWorkflow;

using System.Runtime.Serialization;

 

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;

}

else

{

var xmlRoot = XElement.Load(new StreamReader(filterContext.HttpContext.Request.InputStream,

filterContext.HttpContext.Request.ContentEncoding));

object o = new XmlSerializer(RootType).Deserialize(xmlRoot.CreateReader());

filterContext.ActionParameters[Param] = o;

}

}

}

 

Here is how we apply the custom attribute:

[ObjectFilter(Param="customerInfo", RootType=typeof(CustomerInfo))]
public JsonResult GetCustomer(CustomerInfo searchInfo)
{
  return Json("complete");

}

//  note that the properties Name and Location must match

// the JSON property names exactly, or this won't work.

class CustomerInfo

{
    string Name {get; set;}
    string Location {get; set;}
}