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;}
}

Gary SchiralliPosted Aug 30, 2020, 1:36 AM
I'm a bit lost here. :( Should your Example line of : [ObjectFilter(Param="customerInfo", RootType=typeof(CustomerInfo))] Instead be : [ObjectFilter(Param="searchInfo", RootType=typeof(CustomerInfo))] ...because I don't see what 'customerInfo' is in there?
AymPosted Aug 12, 2010, 10:54 AM
Sorry, if I keep posting this.. don't know if it's posting or not: The problem I am having is, I have a class file in my silverlight project and one in my mvc project. The class file in my silverlight project can not be annotated with [DataContract] and [DataMember] because it will error when I try to return JSON objects from MVC Controller to silverlight. The class file in my MVC project HAS to be annotated with [DataContract] and [DataMember] and in addition, I have to implement IModelBinder because the JSON object will never reach the controller (in scenarios where I need to save an object from silverlight back to controller). Putting the class file into a Silverlight Class Library and referencing the class file from both Silverlight and MVC app doesn't work because I can't reference the namespace System.web.mvc needed for the ModelBinder or ActionFilterAttribute. Now I am left to maintain 2 class files. Any ideas?
Mike GoldPosted Jun 14, 2009, 12:59 AM
I like that you moved the Json Serialization into a model binder. It does seem to be a cleaner approach to passing-in json objects, although about the same amount of effort. It would be nice if json object modelbinders were built into the MVC framework. (Perhaps they already are in the release, I haven't checked)
Stanislav ChernichkinPosted Jun 12, 2009, 4:06 AM
Use custom model binder for custom formats. For example: public class JsonModelBinder: IModelBinder { #region IModelBinder Members public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { if (controllerContext == null) throw new ArgumentNullException("controllerContext"); if (bindingContext == null) throw new ArgumentNullException("bindingContext"); var serializer = new DataContractJsonSerializer(bindingContext.ModelType); return serializer.ReadObject(controllerContext.HttpContext.Request.InputStream); } #endregion } [DataContract] [ModelBinder(typeof(JsonModelBinder))] public class CustomerInfo { [DataMember] string Name { get; set; } [DataMember] string Location { get; set; } } Then you controller method will looks just like: public JsonResult GetCustomer(CustomerInfo searchInfo) { return Json("complete"); }