【问题标题】:Post an Array of Objects via JSON to ASP.Net MVC3通过 JSON 将对象数组发布到 ASP.Net MVC3
【发布时间】:2011-06-14 22:32:41
【问题描述】:

我正在寻找一种通过 JSON 将对象数组发布到 MVC3 的解决方案。

我正在处理的示例代码: http://weblogs.asp.net/scottgu/archive/2010/07/27/introducing-asp-net-mvc-3-preview-1.aspx

JS:

var data = { ItemList: [ {Str: 'hi', Enabled: true} ], X: 1, Y: 2 };

$.ajax({
    url: '/list/save',
    data: JSON.stringify(data),
    success: success,
    error: error,
    type: 'POST',
    contentType: 'application/json, charset=utf-8',
    dataType: 'json'
});

ListViewModel.cs:

public class ListViewModel
{
    public List<ItemViewModel> ItemList { get; set; }
    public float X { get; set; }
    public float Y { get; set; }
}

ItemViewModel.cs:

public class ItemViewModel
{
    public string Str;   // originally posted with: { get; set; }
    public bool Enabled; // originally posted with: { get; set; }
}

ListController.cs:

public ActionResult Save(ListViewModel list)
{
    // Do something
}

这个 POST 的结果:

列表设置为 ListViewModel
它的 X 和 Y 属性已设置
基础 ItemList 属性已设置
ItemList 包含一项,因为它应该
该 ItemList 中的项目未初始化。 Str 为 null 且 Enabled 为 false。

换句话说,这是我从 MVC3 的模型绑定中得到的:

list.X == 1
list.Y == 2
list.ItemList != null
list.ItemList.Count == 1
list.ItemList[0] != null
list.ItemList[0].Str == null

看起来 MVC3 JsonValueProvider 不适用于复杂对象。我怎样才能让它工作?我是否需要修改现有的 MVC3 JsonValueProvider 并修复它?如果是这样,我该如何处理它并在 MVC3 项目中替换它?

相关 StackOverflow 问题我已经追问无济于事:

Asp.net Mvc Ajax Json (post Array) 使用 MVC2 和较旧的基于表单的编码 - 该方法因包含对象数组的对象而失败(JQuery 无法正确编码)。

Post an array of complex objects with JSON, JQuery to ASP.NET MVC Controller 使用我想避免的 hack,控制器改为接收纯字符串,然后手动反序列化自身,而不是利用框架。

MVC3 RC2 JSON Post Binding not working correctly 没有设置他的内容类型 - 它在我的代码中设置。

How to post an array of complex objects with JSON, jQuery to ASP.NET MVC Controller? 这个可怜的家伙不得不写一个 JsonFilter 来解析一个数组。另一个我希望避免的黑客攻击。

那么,我该如何实现呢?

【问题讨论】:

  • 更新:我已经深入研究了 JsonValueProviderFactory。它正确地使用“str”属性并将其作为 Key="ItemList[0].Str", Value="hi" 添加到支持字典中,这看起来是正确的。模型绑定器?
  • 您先生,刚刚收到了一个赞成票和一颗星,因为您出色地执行了堆栈溢出问题! :)
  • 这里也一样,这是最后让它为我工作的那个。谢谢!

标签: arrays json post asp.net-mvc-3


【解决方案1】:

除了{ get; set; }之外,还有一些JSON绑定支持的条件:

  1. 这是 ASP.NET MVC 3 中的新功能(请参阅“JavaScript and AJAX Improvements”)。
  2. JSON 对象的字符串(“X”、“Y”、“Str”和“Enabled”)必须与 ViewModel 对象的属性匹配。
  3. ViewModel 对象的属性必须有{ get; set; } 方法。
  4. 必须在请求中将内容类型指定为“application/json”。
  5. 如果仍然无法正常工作,请检查 JSON 字符串以确保它是有效的。

my post了解更多信息。

希望有帮助!

【讨论】:

  • 感谢您提供详细信息。原来我有一个没有指定'application/json'内容类型的ajax调用,并且在填充数组项属性时一切正常!
  • 对开箱即用的 json biding 支持的要求进行绝对、清晰和简明的概述,以使用 w/asp.net mvc。一个有价值的参考和很好的答案。
【解决方案2】:

问题在于,列表中模型中的属性在其公共属性上没有获取/设置。换句话说,MVC3 的自动 JSON 绑定仅适用于具有 get 和 set 的对象属性。

这不会绑定:

public string Str;

这将绑定:

public string Str { get; set; }

【讨论】:

【解决方案3】:

这很奇怪。我无法重现您的行为。这是我的设置(ASP.NET MVC 3 RTM):

型号:

public class ItemViewModel
{
    public string Str { get; set; }
    public bool Enabled { get; set; }
}

public class ListViewModel
{
    public List<ItemViewModel> ItemList { get; set; }
    public float X { get; set; }
    public float Y { get; set; }
}

控制器:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View();
    }

    [HttpPost]
    public ActionResult Save(ListViewModel list)
    {
        return Json(list);
    }
}

查看:

@{
    ViewBag.Title = "Home Page";
}

<script type="text/javascript">
    $(function () {
        var data = { ItemList: [{ Str: 'hi', Enabled: true}], X: 1, Y: 2 };

        $.ajax({
            url: '@Url.Action("save", "home")',
            data: JSON.stringify(data),
            type: 'POST',
            contentType: 'application/json',
            dataType: 'json',
            success: function (result) {
                alert(result.ItemList[0].Str);
            }
        });
    });
</script>

运行此警报 "hi" 并在 Save 操作中正确初始化所有内容。

为了记录,字典不起作用。关于这个问题,我已经 opened a ticket

【讨论】:

  • 奇怪。感谢您查看这个。值得一提的是,我在这里使用的是 MVC 版本:asp.net/mvc/mvc3 - 我们可能正在使用不同版本的 MVC,但如果最终版本变得更糟会很奇怪。在标记此问题是否已回答之前,我将尝试更好地隔离问题并验证我的问题的断言。
  • 我发现了问题。内部模型使用没有获取/设置的公共属性。我将解决问题以扩展问题。
  • 每个人:注意这一行 >>> contentType: 'application/json'
  • +1:感谢您在这方面不遗余力(带有代码示例)。它帮助了我,我什至不是 OP。
  • 我喜欢这种用于 json 请求的模式,很高兴看到它如此清晰地再现;简单明了,直接且易于解析。我可以使用 resharper 宏来快速添加片段以进行新的端到端 json 调用;完整的 w/view 模型,因为我最近似乎越来越多地使用这种模式。
【解决方案4】:

我遇到了类似的问题,发现对于一个复杂的对象,数值会丢失。他们以零的形式出现。 即

    var person = {
        Name: "john",
        Age: 9
    }

被 MVC 控制器作为 Person 对象接收,其中属性被填充为 Name=JohnAge=0

然后我将 Javascript 中的 Age 值设为字符串...即

    var person = {
        Name: "john",
        Age: "9"
    }

这一切都很好......

【讨论】:

    【解决方案5】:

    这是因为 MVC 绑定器有点糟糕。但是,如果所有 JSON 值都以字符串形式出现,它们确实可以很好地工作。

    如果你这样做,在 JS 中

    var myObject = {thisNumber:1.6};
    
    myObject.thisNumber=myObject.thisNumber-.6;
    

    它将评估为 1 而不是 1.0

    因此,当您将它发送到服务器时,它会尝试绑定到该名称的浮点数,但它不会找到它,因为它以 1 而不是 1.0 的形式出现。 MS工程师没有为此提出默认解决方案,这非常蹩脚和疯狂。我发现如果你把所有东西都串起来,绑定就足够聪明地找到东西了。

    因此,在发送数据之前,通过一个字符串化器运行它,该字符串化器也会将所有值转换为字符串。

    【讨论】:

      【解决方案6】:

      所有以前的答案都很好地指出了类似问题的解决方案。我必须发布 x-www-form-urlencoding 而不是 application/json (如果缺少 contentType 参数,则为默认选项)才能传递 __RequestVerificationToken 并且同时在数组中的对象属性不绑定它们的值时遇到问题。解决问题的方法是了解 MVC 模型绑定器的内部工作。

      因此,基本上,当您需要提供验证令牌时,您会受到验证属性的限制。并且您必须将令牌作为参数提供,而不是作为您发送的 JSON 对象的一部分。如果你不使用ValidateAntiForgeryToken,你可以使用 JSON.stringify。但是,如果您愿意,您将无法传递令牌。

      ContentTypex-www-form-urlencoding 时,我嗅探到后端的流量,并且我注意到我的复杂对象数组被序列化为类似的东西:klo[0][Count]=233&amp;klo[0][Blobs]=94。这个数组最初是根对象的一部分,比方说一些模型。看起来像这样:model.klo = [{ Count: 233, Blobs: 94}, ...]

      在后端,这个klo 属性是由MVC binder 创建的,其元素计数与我发送的相同。但是这些元素本身并没有为其属性获取值。

      解决方案

      为了解决这个问题,我从客户端的模型对象中排除了klo 属性。在ajax 函数中我写了这段代码:

      data: $.param(model) + "&" + arrayOfObjectsToFormEncoding("klo", [{ Count: 233, Blobs: 94}, ...])
      ....
      
          function arrayOfObjectsToFormEncoding (modelPropertyName, arrayOfObjects) {
              var result = "";
              if (arrayOfObjects && typeof arrayOfObjects == "object") {
                  for (var i = 0; i < arrayOfObjects.length; i++) {
                      var obj = arrayOfObjects[i];
                      if (obj) {
                          for (var p in obj) {
                              if (obj.hasOwnProperty(p)) {
                                  result += encodeURIComponent(modelPropertyName + "[" + i + "]." + p) + "=" + encodeURIComponent(obj[p]) + "&";
                              }
                          }
                      }
                  }
              }
      
              if (result[result.length - 1] == "&") {
                  result = result.substr(0, result.length - 1);
              }
      
              return result;
          }
      

      该函数将复杂对象数组转换为 MVC-binder 可识别的形式。表格是klo[0].Count=233&amp;klo[0].Blobs=94

      【讨论】:

        猜你喜欢
        • 2012-10-05
        • 2020-12-03
        • 2023-03-17
        • 2015-09-06
        • 2018-05-23
        • 1970-01-01
        • 1970-01-01
        • 2013-09-08
        • 2020-11-25
        相关资源
        最近更新 更多