通过JSON将对象数组发布到ASP.Net MVC3

时间:2011-01-25 02:39:30

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

我正在寻找通过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来解析一个数组。另一个我宁愿避免的黑客攻击。

那么,我该如何实现呢?

6 个答案:

答案 0 :(得分:43)

{ 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字符串以确保它是有效的。
  6. my post了解详情。

    希望有所帮助!

答案 1 :(得分:30)

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

这不会绑定:

public string Str;

这将绑定:

public string Str { get; set; }

答案 2 :(得分:29)

这很奇怪。我无法重现您的行为。这是我的设置(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关于这个问题。

答案 3 :(得分:3)

我有一个类似的问题,发现对于一个复杂的对象,数字值会被遗漏。他们以零的形式进来。 即。

    var person = {
        Name: "john",
        Age: 9
    }
MVC控制器正在接收

作为Person对象,其中属性被填充为Name=JohnAge=0

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

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

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

答案 4 :(得分:0)

因为MVC粘合剂很糟糕。但是,如果所有JSON值都以字符串形式出现,它们确实可以正常工作。

在JS中如果你这样做

var myObject = {thisNumber:1.6};

myObject.thisNumber=myObject.thisNumber-.6;

它将评估为1而不是1.0

因此,当您将其发送到服务器时,它将尝试绑定到该名称的浮动,并且它将找不到它,因为它是1而不是1.0。 MS工程师没有为此提出默认解决方案,这非常蹩脚和疯狂。我发现如果你把所有绑定都很聪明的东西都用来找东西。

因此,在通过运行它来发送数据之前,它还会将所有值转换为字符串。

答案 5 :(得分:0)

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

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

ContentTypex-www-form-urlencoding时,我向后端嗅到了流量,我说我的复杂对象数组序列化为:klo[0][Count]=233&klo[0][Blobs]=94。这个数组最初是根对象的一部分,让我们说一些模型。它看起来像是:model.klo = [{ Count: 233, Blobs: 94}, ...]

在后端,这个klo属性是由MVC活页夹创建的,具有我发送的相同元素数。但这些元素本身并没有获得其属性的价值。

<强>

为了解决这个问题,我从客户端的模型对象中排除了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&klo[0].Blobs=94