如何将字典作为参数传递给 jQuery/Ajax 的 ActionResult 方法?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1077481/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I pass a Dictionary as a parameter to an ActionResult method from jQuery/Ajax?
提问by Chris Pietschmann
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.
我正在使用 jQuery 在 ASP.NET MVC 中使用 Http Post 进行 Ajax 调用。我希望能够传递一个值字典。
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.
我能想到的最接近的事情是传入一个多维字符串数组,但实际传递给 ActionResult 方法的结果是一个包含“键/值”对字符串串联的单维字符串数组。
For instance the first item in the below "values" array contains the below value:
例如,下面“values”数组中的第一项包含以下值:
"id,200"
Here's an example of my ActionResult method:
这是我的 ActionResult 方法的示例:
public ActionResult AddItems(string[] values)
{
// do something
}
Here's an example of how I'm calling the method from jQuery:
这是我如何从 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?
有谁知道如何将一个 Dictionary 对象从 jQuery 传递给 ActionResult 方法而不是一个数组?
I would really like to define my ActionResult like this:
我真的很想像这样定义我的 ActionResult:
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";
采纳答案by Chris Pietschmann
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.
我终于明白了!!谢谢大家的建议!我终于找到了最好的解决方案是通过 Http Post 传递 JSON 并使用自定义 ModelBinder 将 JSON 转换为字典。我在解决方案中做的一件事是创建了一个继承自 Dictionary 的 JsonDictionary 对象,以便我可以将自定义 ModelBinder 附加到 JsonDictionary 类型,并且如果我稍后将 Dictionary 作为 ActionResult 参数用于与 JSON 不同的目的。
Here's the final ActionResult method:
这是最终的 ActionResult 方法:
public ActionResult AddItems([Bind(Include="values")] JsonDictionary values)
{
// do something
}
And the jQuery "$.post" call:
和 jQuery "$.post" 调用:
$.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:
然后需要注册 JsonDictionaryModelBinder,我将其添加到 Global.asax.cs 中的 Application_Start 方法中:
protected void Application_Start()
{
ModelBinders.Binders.Add(typeof(JsonDictionary), new JsonDictionaryModelBinder());
}
And, finally here's the JsonDictionaryModelBinder object and JsonDictionary object I created:
最后,这是我创建的 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);
}
}
回答by shwetaOnStack
This is what I tried. Saves a lot of work. Javascript:
这是我尝试过的。节省了大量的工作。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; }
}
回答by Arnis Lapsa
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.
使用自定义模型绑定器或过滤器是可能的。在幕后 - 无论如何您都必须手动完成(Request.Form,解析字符串,创建字典 tralala),但至少 - 您的控制器将是干净的,并且代码将可重用于其他操作。
回答by Chris Pietschmann
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.
我认为不可能通过 Http Post 将字典从 jQuery/Ajax 传递到 ActionResult 方法。我发现似乎最容易处理的一件事是传入 JSON 对象,然后将其解析为字典。
Here's the modified version of of the above calling "$.post" from jQuery that sends JSON as a pseudo-Dictionary:
这是上面从 jQuery 调用 "$.post" 的修改版本,它将 JSON 作为伪字典发送:
$.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.
“Sys.Serialization.JavaScriptSerializer.serialize”函数是 ASP.NET AJAX JavaScript 库的一种方法。
Here's the modified version of the above ActionResult method:
这是上述 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
}
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.
我认为通过传递 JSON 而不是使用表单集合来发送/检索键/值对的集合,这使得单元测试变得更加容易。此外,与弄清楚如何构建自定义 IModelBinder 相比,开始工作更容易,并且当这是我唯一需要执行此操作的方法时,自定义 IModelBinder 可能会导致其他 ActionResult 方法出现问题。
回答by eu-ge-ne
DefaultModelBinder is able to bind your POST to array or dictionary. For example:
DefaultModelBinder 能够将您的 POST 绑定到数组或字典。例如:
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:
如果您的值在 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");
UPDATED:
更新:
Also check this: Scott Hanselman's ComputerZen.com - ASP.NET Wire Format for Model Binding to Arrays, Lists, Collections, Dictionaries
回答by Jeroen
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.
@eu-ge-ne:“DefaultModelBinder 能够将您的 POST 绑定到数组或字典。” 没错,但至少对于字典,我发现所需的形式符号相当违反直觉。
@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.
@Chris:昨天我在尝试将 JavaScript (JSON) 字典发布到控制器操作方法时遇到了完全相同的问题。我制定了一个完全不同的自定义模型绑定器,它处理具有不同类型参数的通用字典。我只在 MVC 3 中测试过它,并且可能具有改进框架的优势。
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
有关我的经验和自定义模型绑定器的源代码的详细信息,请参阅我在http://buildingwebapps.blogspot.com/2012/01/passing-javascript-json-dictionary-to.html 上的博客文章