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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1474896/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 17:54:28  来源:igfitidea点击:

In ASP.NET MVC, deserialize JSON prior to or in controller's action method

c#jqueryasp.net-mvcjson

提问by weilin8

I am working on a website that will post a JSON object (using jQuery Post method) to the server side.

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

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

At the same time, I wrote classes on the server side for this data structure.

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

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

When I run the website with following code in my controller class, the FullName property doesn't get deserialized. What am I doing wrong?

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

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

    return View();
}

采纳答案by weilin8

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 takeparadescribed above. But I don't really know that pros and cons of doing in either approach.

我通过实现一个动作过滤器解决了我的问题;下面提供了代码示例。从研究,我了解到,有另一种解决方案,模型绑定,如takepara如上所述。但我真的不知道这两种方法的利弊。

Thanks to Steve Gentile's blog postfor this solution.

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

回答by Ryan Taylor

You could try Json.NET. The documentationis pretty good and it should be able to do what you need. You'll also want to grab JsonNetResultas it returns an ActionResult that can be used in ASP.NET MVC application. It's quite easy to use.

你可以试试Json.NET。该文档是相当不错的,它应该能够做你的需要。您还需要获取JsonNetResult,因为它返回可在 ASP.NET MVC 应用程序中使用的 ActionResult。它很容易使用。

Json.NET also works well with Date serialization. More info regarding that can be found here.

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

Hope this helps.

希望这可以帮助。

回答by takepara

1.create custom model binder

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

      return model;
    }
  }

2.add model binder in application_start event

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

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

3.use jQuery $.get/$.post in view client JavaScript code.

3.在查看客户端JavaScript代码中使用jQuery $.get/$.post。

  <% 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>

回答by CmdrTallen

Try this;

尝试这个;

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

回答by Diego

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:

经过一番研究,我发现 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;
        }
    }
}

Then, in Global.asax.cs, Application_Start():

然后,在 Global.asax.csApplication_Start()

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