Como faço para passar um dictionary como um parâmetro para um método ActionResult de jQuery / Ajax?

Estou usando o jQuery para fazer uma chamada Ajax usando um Http Post no ASP.NET MVC. Eu gostaria de poder passar um dictionary de valores.

A coisa mais próxima que eu poderia pensar era passar em uma multidimensional array de strings, mas o resultado que realmente é passado para o método ActionResult é uma matriz de strings unidimensionais contendo uma concatenação de strings do par “chave / valor”.

Por exemplo, o primeiro item da matriz abaixo “values” contém o valor abaixo:

"id,200" 

Aqui está um exemplo do meu método ActionResult:

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

Aqui está um exemplo de como estou chamando o método de jQuery:

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

Alguém sabe como passar um object Dictionary do jQuery para o método ActionResult em vez de um Array?

Eu realmente gostaria de definir meu ActionResult assim:

 public ActionResult AddItems(Dictionary values) { // do something } 

Alguma sugestão?

ATUALIZAÇÃO: Eu tentei passar uma vírgula dentro do valor e isso basicamente torna impossível realmente analisar o par chave / valor usando a análise de string.

Passe isto:

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

resulta nisso:

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

Finalmente eu descobri !! Obrigado pelas sugestões a todos! Eu finalmente descobri que a melhor solução é passar JSON através do Http Post e usar um ModelBinder personalizado para converter o JSON em um Dicionário. Uma coisa que fiz na minha solução foi criar um object JsonDictionary que herda do Dictionary para que eu possa append o ModelBinder personalizado ao tipo JsonDictionary, e não causará conflitos no futuro se eu usar o Dictionary como um parâmetro ActionResult mais tarde para um finalidade diferente do JSON.

Aqui está o método final do ActionResult:

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

E a chamada “$ .post” do jQuery:

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

Em seguida, o JsonDictionaryModelBinder precisa ser registrado, eu adicionei isso ao método Application_Start dentro do Global.asax.cs:

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

E, finalmente, aqui está o object JsonDictionaryModelBinder e o object JsonDictionary que criei:

 public class JsonDictionary : Dictionary { 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(json); } } 

Isso é o que eu tentei. Economiza muito trabalho. 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"); 

Método de ação:

 public ActionResult MethodName(DictionaryModel obj) { //Action method logic } public class DictionaryModel { public Dictionary dict { get; set; } } 

É possível com ligadores ou filtros de modelo personalizados. Nos bastidores – você terá que fazê-lo manualmente de qualquer maneira (Request.Form, analisar cadeias de caracteres, criar dictionary tralala), mas pelo menos – seu controlador estará limpo e o código será reutilizável para outras ações.

Eu não acho que é possível passar em um dictionary de jQuery / Ajax para um método ActionResult através de um Http Post. Uma coisa que descobri que parece ser a mais fácil de se trabalhar é passar um object JSON e analisá-lo em um Dicionário.

Aqui está a versão modificada da chamada acima “$ .post” do jQuery que envia JSON como um pseudo-dictionary:

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

A function “Sys.Serialization.JavaScriptSerializer.serialize” é um método da biblioteca JavaScript AJAX do ASP.NET.

Aqui está a versão modificada do método ActionResult acima:

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

Eu acho que isso torna muito mais fácil para Unit Test passando JSON, em vez de usar a coleção de formulários para enviar / recuperar a coleção de pares de chave / valor. Além disso, é mais fácil começar a trabalhar do que descobrir como construir um IModelBinder personalizado, e um IModelBinder personalizado pode causar problemas com outros methods ActionResult quando este é o único que preciso fazer isso.

DefaultModelBinder é capaz de vincular seu POST a matriz ou dictionary. Por exemplo:

para matrizes:

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

ou:

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

para dictionarys:

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

ATUALIZADA:

Se seus valores estão em inputs HTML, então no jQuery você pode fazer algo assim:

 var postData = $('input#id1, input#id2, ..., input#idN").serialize(); // or var postData = $('input.classOfYourInputs").serialize(); $.post("/Controller/AddItems", { values: postData }, function(data) { }, "json"); 

ATUALIZADA:

Veja também: ComputerZen.com de Scott Hanselman – ASP.NET Wire Format para Model Binding para Arrays, Lists, Collections, Dictionaries

Este é um post antigo, mas não posso deixar de ter algumas observações de qualquer maneira.

@ eu-ge-ne: “DefaultModelBinder é capaz de ligar o seu POST a array ou dictionary.” É verdade, mas pelo menos para dictionarys eu acho a notação de forma necessária bastante contra-intuitiva.

@ Chris: Ontem eu tive exatamente o mesmo problema ao tentar postar um dictionary JavaScript (JSON) em um método de ação do controlador. Eu trabalhei um fichário de modelo personalizado totalmente diferente que processa dictionarys genéricos com diferentes argumentos de tipo. Eu só testei no MVC 3 e provavelmente tive a vantagem de um framework melhorado.

Para obter detalhes sobre minhas experiências e o código-fonte do fichário de modelos personalizados, consulte minha postagem no blog em http://buildingwebapps.blogspot.com/2012/01/passing-javascript-json-dictionary-to.html

    Intereting Posts