【问题标题】:ASP.NET MVC 4 JSON Binding to the View Model - Nested object errorASP.NET MVC 4 JSON 绑定到视图模型 - 嵌套对象错误
【发布时间】:2013-08-24 18:08:58
【问题描述】:

我遇到了将 json 绑定到视图模型的问题。这是我的代码:

我的 ViewModel 的一部分(AddressViewModel 有更多属性):

public class AddressViewModel
{
        [Display(Name = "Address_Town", ResourceType = typeof(Resources.PartyDetails))]
        public string Town { get; set; }

        [Display(Name = "Address_Country", ResourceType = typeof(Resources.PartyDetails))]
        public Country Country { get; set; }
}

public class Country : EntityBase<string>
{
        public string Name { get; set; }

        protected override void Validate()
        {
            if (string.IsNullOrEmpty(Name))
            {
                base.AddBrokenRule(new BusinessRule("CountryName", "Required"));
            }
        }
}

Javascript:

$(document).on("click", "#addAddress", function () {
            var jsonData = {
                "Town": $('#txt-Town').val(),
                "District": $('#txt-District').val(),
                "Street": $('#txt-Street').val(),
                "PostCode": $('#txt-PostCode').val(),
                "FlatNumber": $('#txt-FlatNumber').val(),
                "PremiseName": $('#txt-PremiseName').val(),
                "PremiseNumber": $('#txt-Premisenumber').val(),
                "Country": {
                    "Name": $('#txt-Country').val(),
                }
            };
            var addressData = JSON.stringify(jsonData);
            $.ajax({
                url: '/Customer/SaveAddress',
                type: "POST",
                dataType: "json",
                contentType: "application/json; charset=utf-8",
                data: addressData,
                success: function (result) {
                    $("#addIndividualAddressDialog").data("kendoWindow").close();
                },
                error: function (result) {
                    alert("Failed");
                }

            });
        });

控制器头:

[HttpPost]
 public ActionResult SaveAddress(AddressViewModel addressViewModel)

这是我在萤火虫中看到的:

这就是我在 VS 中看到的:

如您所见,普通属性绑定正确,但我的嵌套对象(国家/地区)为空。我阅读了很多不同的文章,但我仍然不知道我做错了什么。请帮帮我!

【问题讨论】:

    标签: json asp.net-mvc-4 model-binding


    【解决方案1】:

    您可以保持现有的 ActionMethod 不变,而无需 json 序列化: 在客户端从您的 json 创建一个对象:

    JSON.parse(jsonData)
    

    并在 $.ajax 数据属性中发送。

    或者,不是创建 json,而是创建一个对象:

    var dataObject = new Object();
    dataObject.Town = $('#txt-Town').val();
    dataObject.District = $('#txt-District').val();
    ...
    

    再一次,在 $.ajax 数据属性中发送该对象。

    【讨论】:

    • 这是这个问题的正确答案。无需修改您的服务器端代码,只需从客户端发送它期望的正确类型的对象。
    • 在 ASP.NET MVC 5 中没有 JSON.parse(jsonData)
    • @hexadecimal,JSON.parse 不是 MVC 的一部分,而是 JavaScript,这就是我写 client side 的原因。 MVC 是服务器端!
    【解决方案2】:

    问题出在您的操作方法参数上:

    [HttpPost]
    public ActionResult SaveAddress(AddressViewModel addressViewModel)
    

    当您使用JSON.stringify() 时,您向控制器发送了一个字符串,而不是一个对象!所以,你需要做一些工作来实现你的目标:

    1) 更改您的操作方法参数:

    [HttpPost]
    public ActionResult SaveAddress(string addressViewModel)
    

    2) 将该字符串反序列化为一个对象 - 即 AddressViewModel:

    IList<AddressViewModel> modelObj = new 
    JavaScriptSerializer().Deserialize<IList<AddressViewModel>>(addressViewModel);
    

    因此,您的最终操作方法应如下所示:

    [HttpPost]
    public ActionResult SaveAddress(string addressViewModel)
    {
        IList<AddressViewModel> modelObj = new 
        JavaScriptSerializer().Deserialize<IList<AddressViewModel>>(addressViewModel);
    
        // do what you want with your model object ...
    }
    

    【讨论】:

    • 在更改动作标题并在 javascript 中进行少量更改后,它可以工作了!
    • 这并不是一个真正的惯用解决方案,因为它会绕过 MVC 的验证和绑定功能。一个更好的解决方案是添加一个 JsonModelBinder 并将这个反序列化逻辑放在那里。如果可以通过覆盖 DefaultModelBinder 中的一些方法来完成
    • 如果您的值在form 中,只需将它们序列化并使用具有contentTypeapplication/x-www-form-urlencoded; charset=UTF-8 的ajax 发送它们。如果没有,只需使用form action="javascript:void(0);"&gt; 包装您的输入字段,以便您可以使用jQuery $.serialize() 序列化表单并用作请求的有效负载。
    【解决方案3】:

    其实最好的办法就是去掉

    var addressData = JSON.stringify(jsonData);
    

    line 并发送 jsonData 本身。如果它是一个实际对象而不仅仅是一个字符串,ASP.NET MVC 将自动绑定它。

    Occam's Razor

    【讨论】:

      【解决方案4】:

      很抱歉回答旧线程。在这里您可以使用JsonResult 而不是ActionResult

      这是你的签名

       [HttpPost]
       public ActionResult SaveAddress(AddressViewModel addressViewModel)
      

      它应该看起来像

      [HttpPost]
       public JsonResult SaveAddress(AddressViewModel addressViewModel)
       {
          return Json(status);
       }
      

      如果你使用JsonResult 而不是ActionResult 的好处是你不需要Deserialize

      这里是链接http://codeforcoffee.org/asp-net-mvc-intro-to-mvc-using-binding-json-objects-to-models/,从这个链接你可以得到这个想法。

      【讨论】:

        【解决方案5】:

        或者你可以使用JsonConvert.DeserializeObject&lt;&gt;();

        下面是反序列化JSON.stringify()结果的代码

        IList<AddressViewModel> modelObj = JsonConvert.DeserializeObject<IList<AddressViewModel>>(addressViewModel);
        

        而不是

        JavaScriptSerializer().Deserialize<IList<AddressViewModel>>(addressViewModel);
        

        【讨论】:

          【解决方案6】:
          您必须在 jsonData 变量中引用 Country 对象。 JSON POST 绑定将正常工作。 旧代码: var jsonData = { "镇": $('#txt-Town').val(), "区": $('#txt-District').val(), "街": $('#txt-Street').val(), "邮政编码": $('#txt-PostCode').val(), "FlatNumber": $('#txt-FlatNumber').val(), "前提名称": $('#txt-前提名称').val(), "PremiseNumber": $('#txt-Premisenumber').val(), “国家”: { "名称": $('#txt-Country').val(), } 新代码: var jsonData = { "镇": $('#txt-Town').val(), "区": $('#txt-District').val(), "街": $('#txt-Street').val(), "邮政编码": $('#txt-PostCode').val(), "FlatNumber": $('#txt-FlatNumber').val(), "前提名称": $('#txt-前提名称').val(), "PremiseNumber": $('#txt-Premisenumber').val(), "Country.Name": $('#txt-Country').val(), }

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-07-31
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多