11

我正在使用 jQuery 在 ASP.NET MVC 中使用 Http Post 进行 Ajax 调用。我希望能够传递值字典。

我能想到的最接近的方法是传入一个多维字符串数组,但实际上传递给 ActionResult 方法的结果是一个包含“键/值”对的字符串连接的单维字符串数组。

例如,以下“值”数组中的第一项包含以下值:

"id,200"

这是我的 ActionResult 方法的示例:

public ActionResult AddItems(string[] values)
{
    // do something
}

这是我如何从 jQuery 调用方法的示例:

$.post("/Controller/AddItems",
    {
        values: [
            ["id", "200"],
            ["FirstName", "Chris"],
            ["DynamicItem1", "Some Value"],
            ["DynamicItem2", "Some Other Value"]
        ]
    },
    function(data) { },
    "json");

有谁知道如何将字典对象从 jQuery 传递给 ActionResult 方法而不是数组?

我真的很想像这样定义我的 ActionResult :

public ActionResult AddItems(Dictionary<string, object> values)
{
    // do something
}

有什么建议么?

更新:我尝试在值中传递一个逗号,它基本上只是使得不可能使用字符串解析来实际解析键/值对。

通过这个:

values: [
    ["id", "200,300"],
    ["FirstName", "Chris"]
]

结果是:

values[0] = "id,200,300";
values[1] = "FirstName,Chris";
4

6 回答 6

10

最后我想通了!!谢谢大家的建议!我终于想出最好的解决方案是通过 Http Post 传递 JSON 并使用自定义 ModelBinder 将 JSON 转换为字典。我在我的解决方案中做的一件事是创建了一个继承自 Dictionary 的 JsonDictionary 对象,以便我可以将自定义 ModelBinder 附加到 JsonDictionary 类型,并且如果我稍后将 Dictionary 用作 ActionResult 参数,它将不会导致任何冲突与 JSON 不同的目的。

这是最终的 ActionResult 方法:

public ActionResult AddItems([Bind(Include="values")] JsonDictionary values)
{
    // do something
}

和 jQuery "$.post" 调用:

$.post("/Controller/AddItems",
{
    values: Sys.Serialization.JavaScriptSerializer.serialize(
            {
                id: 200,
                "name": "Chris"
            }
        )
},
function(data) { },
"json");

然后需要注册 JsonDictionaryModelBinder,我在 Global.asax.cs 中的 Application_Start 方法中添加了这个:

protected void Application_Start()
{
    ModelBinders.Binders.Add(typeof(JsonDictionary), new JsonDictionaryModelBinder());
}

最后,这是我创建的 JsonDictionaryModelBinder 对象和 JsonDictionary 对象:

public class JsonDictionary : Dictionary<string, object>
{
    public JsonDictionary() { }

    public void Add(JsonDictionary jsonDictionary)
    {
        if (jsonDictionary != null)
        {
            foreach (var k in jsonDictionary.Keys)
            {
                this.Add(k, jsonDictionary[k]);
            }
        }
    }
}

public class JsonDictionaryModelBinder : IModelBinder
{
    #region IModelBinder Members

    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        if (bindingContext.Model == null) { bindingContext.Model = new JsonDictionary(); }
        var model = bindingContext.Model as JsonDictionary;

        if (bindingContext.ModelType == typeof(JsonDictionary))
        {
            // Deserialize each form/querystring item specified in the "includeProperties"
            // parameter that was passed to the "UpdateModel" method call

            // Check/Add Form Collection
            this.addRequestValues(
                model,
                controllerContext.RequestContext.HttpContext.Request.Form,
                controllerContext, bindingContext);

            // Check/Add QueryString Collection
            this.addRequestValues(
                model,
                controllerContext.RequestContext.HttpContext.Request.QueryString,
                controllerContext, bindingContext);
        }

        return model;
    }

    #endregion

    private void addRequestValues(JsonDictionary model, NameValueCollection nameValueCollection, ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        foreach (string key in nameValueCollection.Keys)
        {
            if (bindingContext.PropertyFilter(key))
            {
                var jsonText = nameValueCollection[key];
                var newModel = deserializeJson(jsonText);
                // Add the new JSON key/value pairs to the Model
                model.Add(newModel);
            }
        }
    }

    private JsonDictionary deserializeJson(string json)
    {
        // Must Reference "System.Web.Extensions" in order to use the JavaScriptSerializer
        var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
        return serializer.Deserialize<JsonDictionary>(json);
    }
}
于 2009-07-03T20:23:41.003 回答
4

这是我尝试过的。节省大量工作。Javascript:

  var dict = {};       
        dict["id"] = "200";
        dict["FirstName"] = "Chris";
        dict["DynamicItem1"] = "Some Value";
        dict["DynamicItem2"] = "Some Other Value";

        var theObject = {};
        theObject.dict = dict;
        $.post(URL, theObject, function (data, textStatus, XMLHttpRequest) {
            console.log("success");
        }, "json");

行动方法:

public ActionResult MethodName(DictionaryModel obj)
    {
       //Action method logic
    }

public class DictionaryModel
{
    public Dictionary<string, string> dict { get; set; }

}
于 2014-10-21T08:56:26.450 回答
1

可以使用自定义模型绑定器或过滤器。在幕后 - 无论如何您都必须手动完成(Request.Form,解析字符串,创建字典 tralala),但至少 - 您的控制器将是干净的并且代码将可重用于其他操作。

于 2009-07-03T02:16:23.327 回答
1

我认为不可能通过 Http Post 将字典从 jQuery/Ajax 传递到 ActionResult 方法。我发现似乎最容易使用的一件事是传入一个 JSON 对象,然后将其解析为字典。

这是上面从 jQuery 调用“$.post”的修改版本,它将 JSON 作为伪字典发送:

$.post("/Controller/AddItems",
    {
        values: Sys.Serialization.JavaScriptSerializer.serialize(
                {
                    id: 200,
                    "name": "Chris"
                }
            )
    },
    function(data) { },
    "json");

“Sys.Serialization.JavaScriptSerializer.serialize”函数是 ASP.NET AJAX JavaScript 库的一种方法。

这是上述 ActionResult 方法的修改版本:

public ActionResult AddItems(Dictionary<string, object> values)
{
    // Must Reference "System.Web.Extensions" in order to use the JavaScriptSerializer
    var json = new System.Web.Script.Serialization.JavaScriptSerializer();
    var data = json.Deserialize<Dictionary<string, string>>(routeValues);

    // do something
}

我认为这使得通过传递 JSON 进行单元测试变得更加容易,而不是使用表单集合来发送/检索键/值对的集合。此外,开始工作比弄清楚如何构建自定义 IModelBinder 更容易,并且当我需要这样做时,自定义 IModelBinder 可能会导致其他 ActionResult 方法出现问题。

于 2009-07-03T03:02:47.677 回答
0

DefaultModelBinder 能够将您的 POST 绑定到数组或字典。例如:

对于数组:

public ActionResult AddItems(string[] values)

$.post("/Controller/AddItems", { values: "values[0]=200&values[1]=300" },
    function(data) { }, "json");

或者:

$.post("/Controller/AddItems", { values: "values=200&values=300" },
    function(data) { }, "json");

对于字典:

public ActionResult AddItems(Dictionary<string, object> values)

$.post("/Controller/AddItems", {
    values: "values[0].Key=value0&values[0].Value=200&values[1].Key=value1&values[1].Value=300" }, function(data) { }, "json");

更新:

如果您的值在 HTML 输入中,那么在 jQuery 中您可以执行以下操作:

var postData = $('input#id1, input#id2, ..., input#idN").serialize();
// or
var postData = $('input.classOfYourInputs").serialize();

$.post("/Controller/AddItems", { values: postData }, function(data) { }, "json");

更新:

另请查看:Scott Hanselman's ComputerZen.com - ASP.NET Wire Format for Model Binding to Arrays, Lists, Collections, Dictionaries

于 2009-07-03T09:15:12.847 回答
0

这是一个旧帖子,但无论如何我还是忍不住要说几句。

@eu-ge-ne:“DefaultModelBinder 能够将您的 POST 绑定到数组或字典。” 没错,但至少对于字典,我发现所需的形式符号相当违反直觉。

@Chris:昨天我在尝试将 JavaScript (JSON) 字典发布到控制器操作方法时遇到了完全相同的问题。我制定了一个完全不同的自定义模型绑定器,它处理具有不同类型参数的通用字典。我只在 MVC 3 中对其进行了测试,并且可能具有改进框架的优势。

有关我的经验和自定义模型绑定器的源代码的详细信息,请参阅我的博客文章http://buildingwebapps.blogspot.com/2012/01/passing-javascript-json-dictionary-to.html

于 2012-01-19T09:27:18.983 回答