【问题标题】:ASP.NET MVC: How to create a model that will bind to this POSTed data?ASP.NET MVC:如何创建将绑定到此 POST 数据的模型?
【发布时间】:2013-02-11 22:10:21
【问题描述】:

我在创建将绑定到以下表单数据的模型时遇到问题。我遇到的主要困难是创建一个绑定filter 的模型(即:多维数组)。

这是我目前所拥有的。谁能帮我让这个模型正确绑定?

 public class GetPagedRequest
    {
        public int Start { set; get; }

        public int Limit { set; get; }

        public string dir { set; get; }

        public List<FilterRequest> filter { set; get; } //This won't bind properly

    }

    public class FilterRequest
    {
        public string field { set; get; }

        public DataFilterRequest data { set; get; }
    }

    public class DataFilterRequest
    {
        public string type { set; get; }
        public string value { set; get; }

    }

【问题讨论】:

  • 可以添加您目前的表单布局吗?
  • 您已经有一个可以正确绑定的模型。问题是您如何在视图中构建表单。您需要包含该信息,以便我们可以告诉您您做错了什么。
  • 我正在使用 Ext JS 的第三方 Javascript Grid 控件。我没有使用表单来构建和发布数据。 dev.sencha.com/deploy/ext-3.4.0/examples/grid-filtering/…
  • @burtn1ce 你想用模型填充 Ext.ux.grid.GridFilters 吗?我们需要更多关于您正在使用的煎茶代码的详细信息以提供帮助。

标签: asp.net-mvc model


【解决方案1】:

我不支持 jherrera 的解决方案:

[HttpPost]
public ActionResult ReceivePostFromJson()
{
    string jsonStringify = new System.IO.StreamReader(Request.InputStream).ReadToEnd();
    var obj = new JavaScriptSerializer().Deserialize<GetPagedRequest>(jsonStringify);

    return View(obj);
}

如果你想从服务器端的客户端接收 json 数据,你应该准备你的客户端对象,使其具有类似于服务器端视图模型的保存结构。这样,模型绑定器将在提交表单时完美地完成其工作。

代码未测试:

public ActionResult DeleteXXX(GetPagedRequest pagedRequestViewModel)
{
   // Use AutoMapper or a UI Service to reshape/map your viewmodel to your domain model
   return EmptyResult();
}

【讨论】:

    【解决方案2】:

    更新

    看了DefaultModelBinder的能力后,在post数据中看到了问题。

    在任何事情之前,只需将过滤器属性的类更改为:

    public IList<FilterRequest> filter { set; get; } //(IList<T> instead of List<T>)
    

    这是 DefaultModelBinder 将正确绑定的查询字符串:

    start=0&limit=5&dir=ASC&sort=noSort&filter[0].field=CompanyName&filter[0].data.type=string&filter[0].data.value=Telus&filter[1].field=VendorName&filter[1].data.type=string&filter[1].data.value=testtest
    

    但是js正在生成这个查询字符串:

    start=0&limit=5&dir=ASC&sort=noSort&filter[0][field]=CompanyName&filter[0][data][type]=string&filter[0][data][value]=Telus&filter[1][field]=VendorName&filter[1][data][type]=string&filter[1][data][value]=testtest
    

    现在您可以实现自己的 ModelBinder 类,但我认为在客户端序列化对象更容易,只需确保正确设置内容类型即可。这是一个用jquery制作的例子:

    <script type="text/javascript">
        $(function () {
            $("#btnSendPost").click(function () {
                var filterData = {
                    "start": 0, "limit": 5,
                    "dir": "ASC", "sort": "noSort",
                    "filter": [{ "field": "CompanyName", "data": { "type": "string", "value": "Telus" } },
                               { "field": "VendorName", "data": { "type": "string", "value": "testtest" } }]};
                $.ajax({
                    type: "POST",
                    url: "/Home/ReceivePostFromJson",
                    data: JSON.stringify(filterData),
                    dataType: "json",
                    contentType: 'application/json; charset=utf-8'
                });
            });
        });
    </script>
    

    然后您只需将此行添加到 global.asax 文件中的 Application_Start 方法:

    ValueProviderFactories.Factories.Add(new JsonValueProviderFactory());
    

    这样框架将正确绑定模型,并且在 action 方法中您将收到对象

        [HttpPost]
        public ActionResult ReceivePostFromJson(GetPagedRequest g)
        {
    

    原答案

    如果您可以在发布过滤器数据之前将控件中的 json 字符串化,那么您可以使用 JavaScriptSerializer 来反序列化对象。

    这个例子是用jquery制作的:

    <script type="text/javascript">
        $(function () {
            $("#btnSendPost").click(function () {
                var filterData = {
                    "start": 0, "limit": 5,
                    "dir": "ASC", "sort": "VendorName",
                    "filter": [{ "field": "CompanyName", "data": { "type": "string", "value": "Telus" } },
                               { "field": "VendorName", "data": { "type": "string", "value": "testtest" } }]};
                $.ajax({
                    type: "POST",
                    url: "/Home/ReceivePostFromJson",
                    data: JSON.stringify(filterData),
                    dataType: "application/json"
                });
            });
        });
    </script>
    

    然后在控制器中:

    [HttpPost]
    public ActionResult ReceivePostFromJson()
    {
        string jsonStringify = new System.IO.StreamReader(Request.InputStream).ReadToEnd();
        var obj = new JavaScriptSerializer().Deserialize<GetPagedRequest>(jsonStringify);
    
        return View(obj);
    }
    

    这样你就有了嵌套对象:

    注意:在本例中,如果您删除函数 JSON.stringify (data: filterData,),您将在控制器端看到产生问题的查询字符串 (filter[0] [字段]:公司名称)。我不知道是否有办法恢复 json,如果可能的话,你不必修改网格控件:

    【讨论】:

    • 为什么要序列化数据?
    • JavaScriptSerializer 不需要属性 [Serializable],我会从答案中删除它。 DataContractJsonSerializer 确实需要 [Serializable]
    • 如果引用js中的数据,是为了防止对象转化为查询字符串;这样对象被字符串化并且没有额外的转换,然后可以在服务器端检索字符串并反序列化。
    • 嗨,Elisa,我不得不在这里评论你的答案;我理解你的观点事实上我一直鼓励使用框架的标准机制。但是在这种情况下,从我的角度来看,该控件是第 3 方控件,最好的集成是需要对第 3 方组件进行少量修改的控件,由于框架提供的数据无法反序列化查询字符串后,这就是为什么我建议将对象变为 JSON 字符串,并在服务器上使用另一个反序列化器类,在这种情况下为“JavaScriptSerializer”。这就是为什么我说“如果你可以字符串化”
    • 顺便说一句,如果您不想触摸网格控件,则必须 implement your own model binder 这比在 js 上添加 JSON.stringify 更“复杂”。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-03
    • 2014-04-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多