I am working on a website that will post a JSON object (using jQuery Post method) to the server side.
{
\"ID\" : 1,
\"FullName\" : {
\"First
Try this;
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Submit(FormCollection collection)
{
User submittedUser = JsonConvert.DeserializeObject<User>(collection["user"]);
return View();
}
1.create custom model binder
public class UserModelBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
User model;
if(controllerContext.RequestContext.HttpContext.Request.AcceptTypes.Contains("application/json"))
{
var serializer = new JavaScriptSerializer();
var form = controllerContext.RequestContext.HttpContext.Request.Form.ToString();
model = serializer.Deserialize<User>(HttpUtility.UrlDecode(form));
}
else
{
model = (User)ModelBinders.Binders.DefaultBinder.BindModel(controllerContext, bindingContext);
}
return model;
}
}
2.add model binder in application_start event
ModelBinders.Binders[typeof(User)] = new UserModelBinder();
3.use jQuery $.get/$.post in view client JavaScript code.
<% using(Html.BeginForm("JsonData","Home",new{},FormMethod.Post, new{id="jsonform"})) { %>
<% = Html.TextArea("jsonarea","",new {id="jsonarea"}) %><br />
<input type="button" id="getjson" value="Get Json" />
<input type="button" id="postjson" value="Post Json" />
<% } %>
<script type="text/javascript">
$(function() {
$('#getjson').click(function() {
$.get($('#jsonform').attr('action'), function(data) {
$('#jsonarea').val(data);
});
});
$('#postjson').click(function() {
$.post($('#jsonform').attr('action'), $('#jsonarea').val(), function(data) {
alert("posted!");
},"json");
});
});
</script>
I resolved my problem by implementing an action filter; code sample is provided below. From the research, I learned that there is another solution, model binder, as takepara described above. But I don't really know that pros and cons of doing in either approach.
Thanks to Steve Gentile's blog post for this solution.
public class JsonFilter : ActionFilterAttribute
{
public string Parameter { get; set; }
public Type JsonDataType { get; set; }
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.HttpContext.Request.ContentType.Contains("application/json"))
{
string inputContent;
using (var sr = new StreamReader(filterContext.HttpContext.Request.InputStream))
{
inputContent = sr.ReadToEnd();
}
var result = JsonConvert.DeserializeObject(inputContent, JsonDataType);
filterContext.ActionParameters[Parameter] = result;
}
}
}
[AcceptVerbs(HttpVerbs.Post)]
[JsonFilter(Parameter="user", JsonDataType=typeof(User))]
public ActionResult Submit(User user)
{
// user object is deserialized properly prior to execution of Submit() function
return View();
}
You could try Json.NET. The documentation is pretty good and it should be able to do what you need. You'll also want to grab JsonNetResult as it returns an ActionResult that can be used in ASP.NET MVC application. It's quite easy to use.
Json.NET also works well with Date serialization. More info regarding that can be found here.
Hope this helps.
After some research, I found Takepara's solution to be the best option for replacing the default MVC JSON deserializer with Newtonsoft's Json.NET. It can also be generalized to all types in an assembly as follows:
using Newtonsoft.Json;
namespace MySite.Web
{
public class MyModelBinder : IModelBinder
{
// make a new Json serializer
protected static JsonSerializer jsonSerializer = null;
static MyModelBinder()
{
JsonSerializerSettings settings = new JsonSerializerSettings();
// Set custom serialization settings.
settings.DateTimeZoneHandling= DateTimeZoneHandling.Utc;
jsonSerializer = JsonSerializer.Create(settings);
}
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
object model;
if (bindingContext.ModelType.Assembly == "MyDtoAssembly")
{
var s = controllerContext.RequestContext.HttpContext.Request.InputStream;
s.Seek(0, SeekOrigin.Begin);
using (var sw = new StreamReader(s))
{
model = jsonSerializer.Deserialize(sw, bindingContext.ModelType);
}
}
else
{
model = ModelBinders.Binders.DefaultBinder.BindModel(controllerContext, bindingContext);
}
return model;
}
}
}
Then, in Global.asax.cs
, Application_Start()
:
var asmDto = typeof(SomeDto).Assembly;
foreach (var t in asmDto.GetTypes())
{
ModelBinders.Binders[t] = new MyModelBinder();
}