在ASP.NET MVC中,在控制器的操作方法之前或之中反序列化JSON

我正在开发一个网站,它将JSON对象(使用jQuery Post方法)发布到服务器端。

{ "ID" : 1, "FullName" : { "FirstName" : "John", "LastName" : "Smith" } } 

与此同时,我在服务器端为这个数据结构编写了类。

 public class User { public int ID { get; set; } public Name FullName { get; set;} } public class Name { public string FirstName { get; set; } public string LastName { get; set; } } 

当我在我的控制器类中使用以下代码运行网站时,FullName属性不会被反序列化。 我究竟做错了什么?

 [AcceptVerbs(HttpVerbs.Post)] public ActionResult Submit(User user) { // At this point, user.FullName is NULL. return View(); } 

我通过实施动作filter解决了我的问题; 代码示例如下。 从研究中我了解到,还有另一种解决方案,模型粘合剂,如上所述的takepara 。 但我真的不知道这两种方法的优点和缺点。

感谢Steve Gentile关于此解决方案的博客文章 。

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

1.创建自定义模型绑定器

  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(HttpUtility.UrlDecode(form)); } else { model = (User)ModelBinders.Binders.DefaultBinder.BindModel(controllerContext, bindingContext); } return model; } } 

2.在application_start事件中添加模型绑定器

  ModelBinders.Binders[typeof(User)] = new UserModelBinder(); 

3.使用jQuery $ .get / $。发布视图客户端JavaScript代码。

  <% using(Html.BeginForm("JsonData","Home",new{},FormMethod.Post, new{id="jsonform"})) { %> <% = Html.TextArea("jsonarea","",new {id="jsonarea"}) %>
<% } %>

你可以尝试Json.NET 。 文档非常好,应该能够满足您的需求 。 您还需要抓取JsonNetResult,因为它返回可以在ASP.NET MVC应用程序中使用的ActionResult。 它很容易使用。

Json.NET也适用于日期序列化。 有关这方面的更多信息可以在这里找到 。

希望这可以帮助。

试试这个;

 [AcceptVerbs(HttpVerbs.Post)] public ActionResult Submit(FormCollection collection) { User submittedUser = JsonConvert.DeserializeObject(collection["user"]); return View(); } 

经过一些研究,我发现Takepara的解决方案是用Newtonsoft的Json.NET替换默认的MVC JSON解串器的最佳选择。 它也可以推广到程序集中的所有类型,如下所示:

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

然后,在Global.asax.csApplication_Start()

  var asmDto = typeof(SomeDto).Assembly; foreach (var t in asmDto.GetTypes()) { ModelBinders.Binders[t] = new MyModelBinder(); }