2009-07-03 14 views
11

Sto utilizzando jQuery per effettuare una chiamata Ajax utilizzando un post Http in ASP.NET MVC. Mi piacerebbe essere in grado di passare un dizionario di valori.Come posso passare un dizionario come parametro ad un metodo ActionResult da jQuery/Ajax?

La cosa più vicina a cui potevo pensare era passare una matrice multidimensionale di stringhe, ma il risultato che viene effettivamente passato al metodo ActionResult è un array di stringhe monodimensionali contenente una stringa di concatenazione della "chiave/valore" " paio.

Per esempio il primo elemento dell'array sotto "valori" contiene il valore al di sotto:

"id,200" 

Ecco un esempio del mio metodo ActionResult:

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

Ecco un esempio di come I' m chiamando il metodo da jQuery:

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

Qualcuno sa come passare un dizionario o bject da jQuery al metodo ActionResult invece di una matrice?

Mi piacerebbe davvero definire il mio ActionResult in questo modo:

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

Qualche suggerimento?

UPDATE: Ho tentato di inserire una virgola all'interno del valore e fondamentalmente rende impossibile analizzare effettivamente la coppia chiave/valore utilizzando l'analisi delle stringhe.

passare questo:

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

risultati in questo:

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

Non credo ci sia un modo per fare that.I può essere sbagliato, ma sarà banale per analizzare i dati passati in un array di stringhe e creare autonomamente il dizionario all'interno del metodo AddItems. –

+0

Non sono sicuro quali problemi di analisi siano causati da virgole nei valori. –

+0

Finalmente l'ho capito, grazie a tutti quelli che hanno fatto dei suggerimenti! Ho aggiunto la mia soluzione finale come risposta qui sotto. La contrassegnerò come risposta corretta non appena me lo consentirà. Grazie a tutti! –

risposta

11

Finalmente ho capito !! Grazie per i suggerimenti a tutti! Alla fine ho capito che la soluzione migliore è passare JSON tramite Http Post e utilizzare un ModelBinder personalizzato per convertire il JSON in un dizionario. Una cosa che ho fatto nella mia soluzione è stata creare un oggetto JsonDictionary che eredita dal dizionario in modo che io possa collegare il ModelBinder personalizzato al tipo JsonDictionary, e non causerà alcun conflitto in futuro se uso il Dizionario come parametro ActionResult in seguito per un scopo diverso da quello di JSON.

Ecco il metodo ActionResult finale:

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

E il jQuery "$ .post" chiamata:

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

Poi il JsonDictionaryModelBinder deve essere registrata, ho aggiunto questo al metodo Application all'interno the Global.asax.cs:

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

E, infine, ecco JsonDictionaryMode oggetto lBinder e oggetto JsonDictionary ho creato:

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

E 'possibile con leganti modello personalizzato o filtri. Dietro le quinte - dovrai comunque farlo manualmente (Request.Form, analizzare stringhe, creare il dizionario tralala), ma almeno - il tuo controller sarà pulito e il codice sarà riutilizzabile per altre azioni.

1

Non credo sia possibile passare un dizionario da jQuery/Ajax a un metodo ActionResult tramite un Post HTTP. Una cosa che ho capito è che sembra essere il modo più semplice con cui lavorare è passare un oggetto JSON e poi analizzarlo in un dizionario.

Ecco la versione modificata della vocazione sopra "$ .post" da jQuery che trasmette JSON come uno pseudo-dizionario:

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

La funzione "Sys.Serialization.JavaScriptSerializer.serialize" è un metodo della libreria JavaScript di ASP.NET AJAX.

Ecco la versione modificata del metodo ActionResult sopra:

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 
} 

Penso che questo lo rende molto più facile da Unità di prova passando JSON, invece di utilizzare il modulo di raccolta per inviare/recuperare l'insieme di chiave/coppie di valori.Inoltre, è più facile lavorare che capire come creare un IModelBinder personalizzato e un oggetto personalizzato di IModelBinder potrebbe causare problemi con altri metodi ActionResult quando questo è l'unico che devo fare.

+0

Chris, vedere il mio commento sopra. Continuo a pensare che tu stia andando in questo modo nel modo più duro. Non sono sicuro al 100%, ma ho questa sensazione tremenda che tu sia. – griegs

0

DefaultModelBinder è in grado di associare il POST a array o dizionario. Ad esempio:

per array:

public ActionResult AddItems(string[] values) 

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

o:

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

per dizionari:

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

aggiornamento:

Se i valori sono in input HTML allora in jQuery si può fare qualcosa di simile:

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

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

aggiornamento:

verificare anche questo: Scott Hanselman's ComputerZen.com - ASP.NET Wire Format for Model Binding to Arrays, Lists, Collections, Dictionaries

+0

Ho provato il tuo esempio di dizionario, ma non finisce con il popolamento del parametro "valori"; finisce per essere un dizionario vuoto. –

+0

Hai provato Dictionary values ​​invece Dictionary . Controlla anche se il tuo indice [n] valori è a base zero e ininterrotto. Controlla http://stackoverflow.com/questions/1031416/asp-net-mvc-model-binding-a-set-of-dynamically-generated-checkboxes-how-to/1031694#1031694 anche –

0

questo è un vecchio post, ma non posso evitare di avere un paio di osservazioni in ogni caso.

@ eu-ge-ne: "DefaultModelBinder è in grado di associare il POST a array o dizionario." Vero ma almeno per i dizionari trovo la notazione del modulo richiesta piuttosto controintuitiva.

@Chris: Ieri ho avuto esattamente lo stesso problema durante il tentativo di pubblicare un dizionario JavaScript (JSON) su un metodo di azione del controller. Ho elaborato un raccoglitore di modelli personalizzati completamente diverso che elabora dizionari generici con argomenti di tipo diverso. L'ho provato solo in MVC 3 e probabilmente ho avuto il vantaggio di un framework migliorato.

Per i dettagli delle mie esperienze e il codice sorgente del modello personalizzato legante, si prega di vedere il mio post sul blog a http://buildingwebapps.blogspot.com/2012/01/passing-javascript-json-dictionary-to.html

2

Questo è quello che ho provato. Risparmia molto lavoro. 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"); 

Azione Metodo:

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

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

} 
+0

Non esattamente quello che volevo, perché non c'è motivo di passare un oggetto, se si potesse semplicemente passare il dizionario stesso ma questo funziona abbastanza bene. Upvoted. :) –

Problemi correlati