如何将字典作为参数从 jQuery/Ajax 传递给 ActionResult 方法?

发布于 2024-07-25 21:05:21 字数 1186 浏览 3 评论 0原文

我正在使用 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 传递 Dictionary 对象到 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";

I'm using jQuery to make an Ajax call using an Http Post in ASP.NET MVC. I would like to be able to pass a Dictionary of values.

The closest thing I could think of was to pass in a multi-dimensional array of strings, but the result that actually gets passed to the ActionResult method is a single dimensional string array containing a string concatenation of the "key/value" pair.

For instance the first item in the below "values" array contains the below value:

"id,200"

Here's an example of my ActionResult method:

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

Here's an example of how I'm calling the method from jQuery:

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

Does anyone know how to pass a Dictionary object from jQuery to the ActionResult method instead of an Array?

I would really like to define my ActionResult like this:

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

Any suggestions?

UPDATE: I tried passing in a comma within the value and it basically just makes it impossible to actually parse the key/value pair using string parsing.

Pass this:

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

results in this:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

茶花眉 2024-08-01 21:05:21

终于我想通了!! 谢谢大家的建议! 我最终发现最好的解决方案是通过 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 对象 I创建:

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);
    }
}

At last I figured it out!! Thanks for the suggestions everyone! I finally figured out the best solution is to pass JSON via the Http Post and use a custom ModelBinder to convert the JSON to a Dictionary. One thing I did in my solution is created a JsonDictionary object that inherits from Dictionary so that I can attach the custom ModelBinder to the JsonDictionary type, and it wont cause any conflicts in the future if I use Dictionary as a ActionResult parameter later on for a different purpose than JSON.

Here's the final ActionResult method:

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

And the jQuery "$.post" call:

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

Then the JsonDictionaryModelBinder needs to be registered, I added this to the Application_Start method within the Global.asax.cs:

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

And, finally here's the JsonDictionaryModelBinder object and JsonDictionary object I created:

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);
    }
}
酒儿 2024-08-01 21:05:21

这就是我尝试过的。 节省大量工作。
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; }

}

This is what I tried. Saves a lot of work.
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");

Action Method:

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

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

}
沐歌 2024-08-01 21:05:21

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

It's possible with custom model binders or filters. Behind the scenes - you will have to do it manually anyway (Request.Form, parse strings, create dictionary tralala), but at least - your controller will be clean and code will be reusable for another actions.

梦里兽 2024-08-01 21:05:21

我认为不可能通过 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 方法出现问题。

I don't think it's possible to pass in a Dictionary from jQuery/Ajax to an ActionResult method via an Http Post. One thing I figured out that seems to be the easiest to work with is to pass in a JSON object and then parse that out into a Dictionary.

Here's the modified version of of the above calling "$.post" from jQuery that sends JSON as a pseudo-Dictionary:

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

The "Sys.Serialization.JavaScriptSerializer.serialize" function is a method of the ASP.NET AJAX JavaScript library.

Here's the modified version of the above ActionResult method:

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
}

I think this makes it much easier to Unit Test by passing JSON, instead of using the Form Collection to send/retrieve the collection of key/value pairs. Also, it's easier to get working than figuring out how to build a custom IModelBinder, and a custom IModelBinder might cause issues with other ActionResult methods when this is the only one I need to do this.

傾旎 2024-08-01 21:05:21

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 的 ComputerZen.com - 用于模型绑定到数组、列表、集合、字典的 ASP.NET 有线格式

DefaultModelBinder is able to bind your POST to array or dictionary. For example:

for arrays:

public ActionResult AddItems(string[] values)

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

or:

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

for dictionaries:

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");

UPDATED:

If your values are in HTML inputs then in jQuery you can do something like this:

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

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

UPDATED:

Also check this: Scott Hanselman's ComputerZen.com - ASP.NET Wire Format for Model Binding to Arrays, Lists, Collections, Dictionaries

灯角 2024-08-01 21:05:21

这是一篇旧帖子,但我还是忍不住要说几句。

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

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

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

This is an old post but I can't help having a few remarks anyway.

@eu-ge-ne: "DefaultModelBinder is able to bind your POST to array or dictionary." True but at least for dictionaries I find the required form notation rather counterintuitive.

@Chris: Yesterday I had exactly the same problem while trying to post a JavaScript (JSON) dictionary to a controller action method. I worked out a totally different custom model binder that processes generic dictionaries with different type arguments. I have only tested it in MVC 3 and probably had the advantage of an improved framework.

For the details of my experiences and the source code of the custom model binder, please see my blog post at http://buildingwebapps.blogspot.com/2012/01/passing-javascript-json-dictionary-to.html

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文