2009-07-03 6 views
11

Ich verwende jQuery, um einen Ajax-Aufruf mithilfe eines HTTP-Posts in ASP.NET MVC durchzuführen. Ich würde gerne ein Wörterbuch der Werte weitergeben können.Wie übermittle ich ein Dictionary als Parameter an eine ActionResult-Methode von jQuery/Ajax?

Am nächsten kam mir die Übergabe eines mehrdimensionalen Arrays von Strings, aber das Ergebnis, das an die ActionResult-Methode übergeben wird, ist ein eindimensionales String-Array, das eine String-Verkettung des "key/value" enthält " Paar.

Zum Beispiel das erste Element in der unter „Werte“ Array enthält den folgenden Wert:

"id,200" 

Hier ist ein Beispiel meiner Action Methode:

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

Hier ist ein Beispiel dafür, wie ich m Aufruf der Methode von jQuery:

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

Kann jemand ein Wörterbuch o übergeben bject von jQuery zu der ActionResult-Methode anstelle eines Arrays?

Ich würde wirklich meine Action wie diese gerne definieren:

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

Irgendwelche Vorschläge?

UPDATE: Ich habe versucht, ein Komma innerhalb des Wertes übergeben und es macht im Grunde nur unmöglich, das Schlüssel/Wert-Paar mit String-Parsing tatsächlich analysieren. diese

Pass:

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

Ergebnisse in dieser:

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

Ich glaube nicht, dass es einen Weg gibt, that.I zu tun falsch sein kann, aber es wird trivial, die Daten zu analysieren, als ging in String-Array und erstellen Sie das Wörterbuch selbst innerhalb der AddItems-Methode. –

+0

Nicht sicher, welche Analyseprobleme durch Kommata innerhalb der Werte verursacht werden. –

+0

Endlich habe ich es herausgefunden, danke an alle, die Vorschläge gemacht haben! Ich habe meine endgültige Lösung als Antwort unten hinzugefügt. Ich werde es als die richtige Antwort markieren, sobald SO mich lässt. Danke allen! –

Antwort

11

Endlich habe ich es heraus !! Danke für die Vorschläge alle! Ich habe schließlich herausgefunden, dass die beste Lösung darin besteht, JSON über den HTTP-Post zu übergeben und einen benutzerdefinierten ModelBinder zu verwenden, um den JSON in ein Dictionary zu konvertieren. Eine Sache, die ich in meiner Lösung gemacht habe, ist ein JsonDictionary-Objekt, das von Dictionary erbt, so dass ich den benutzerdefinierten ModelBinder an den JsonDictionary-Typ anhängen kann, und es wird keine Konflikte in der Zukunft verursachen, wenn ich später Dictionary als ActionResult-Parameter für ein verwende anderer Zweck als JSON.

Hier ist das letzte Action Methode:

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

Und die jQuery "$ .post" Aufruf:

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

Dann wird der JsonDictionaryModelBinder registriert werden muss, habe ich diese Methode zum Application_Start hinzugefügt innerhalb die Global.asax.cs:

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

Und schließlich ist hier der JsonDictionaryMode lBinder Objekt und JsonDictionary Objekt I erstellt:

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

Es ist möglich, mit benutzerdefinierten Modell Binder oder Filter. Hinter den Kulissen - Sie müssen es trotzdem manuell tun (Request.Form, Strings analysieren, Wörterbuch-Tralala erstellen), aber zumindest - Ihr Controller wird sauber sein und Code wird für andere Aktionen wiederverwendet werden können.

1

Ich glaube nicht, dass es möglich ist, ein Wörterbuch von jQuery/Ajax über einen HTTP-Post an eine ActionResult-Methode zu übergeben. Eine Sache, die ich herausgefunden habe, scheint die einfachste zu sein, wenn man ein JSON-Objekt eingibt und es dann in ein Dictionary ausgibt.

Hier ist die modifizierte Version des obigen calling "$ .post" von jQuery, die JSON als pseudo-Wörterbuch sendet:

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

Die "Sys.Serialization.JavaScriptSerializer.serialize" -Funktion ist ein Verfahren der ASP.NET AJAX JavaScript-Bibliothek.

Hier ist die modifizierte Version der oben Action Methode:

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 
} 

Ich denke, das es viel einfacher, Unit-Test macht von JSON vorbei, anstatt das Formular Sammlung mit der Sammlung von Schlüsseln zum Senden/Abrufen/Wertpaare.Darüber hinaus ist es einfacher zu arbeiten als herauszufinden, wie ein benutzerdefinierter IModelBinder erstellt wird, und ein benutzerdefinierter IModelBinder kann Probleme mit anderen ActionResult-Methoden verursachen, wenn dies der einzige Vorgang ist, der dies erfordert.

+0

Chris, siehe meinen Kommentar oben. Ich denke immer noch, dass du das auf die harte Tour machst. Ich bin mir nicht 100% sicher, aber ich habe dieses kleine Gefühl, dass du es bist. – griegs

0

DefaultModelBinder kann Ihren POST an ein Array oder ein Wörterbuch binden. Zum Beispiel:

für Arrays:

public ActionResult AddItems(string[] values) 

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

oder:

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

für Wörterbücher:

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

aktualisiert:

Wenn Sie Ihre Werte in HTML Eingaben dann in jQuery sind, können Sie etwas tun:

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

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

AKTUALISIERT:

Auch dies überprüfen: Scott Hanselman's ComputerZen.com - ASP.NET Wire Format for Model Binding to Arrays, Lists, Collections, Dictionaries

+0

Ich habe Ihr Wörterbuch Beispiel versucht, aber es bevölkert nicht den Parameter "Werte"; Es endet einfach damit, ein leeres Wörterbuch zu sein. –

+0

Haben Sie versucht, Dictionary -Werte statt Dictionary . Überprüfen Sie auch, ob Ihr Wert [n] index auf Null basiert und nicht unterbrochen ist. Überprüfen Sie http://StackOverflow.com/questions/1031416/asp-net-mvc-model-binding-a-set-of-dynamically-generated-Checkboxes-how-to/1031694#1031694 auch –

0

Dies ist eine alte Post, aber ich kann ein paar Bemerkungen, die ohnehin nicht helfen.

@ eu-ge-ne: "DefaultModelBinder kann Ihren POST an ein Array oder ein Wörterbuch binden." Richtig, aber zumindest für Wörterbücher finde ich die erforderliche Formnotation eher kontraintuitiv.

@Chris: Gestern hatte ich genau das gleiche Problem beim Versuch, ein JavaScript (JSON) -Wörterbuch zu einer Controller-Aktionsmethode zu veröffentlichen. Ich habe einen völlig anderen benutzerdefinierten Modellbinder ausgearbeitet, der generische Wörterbücher mit unterschiedlichen Typargumenten verarbeitet. Ich habe es nur in MVC 3 getestet und hatte wahrscheinlich den Vorteil eines verbesserten Frameworks.

Für die Details meiner Erfahrungen und den Quellcode des benutzerdefinierten Modell Binder, bitte meine Blog-Post auf http://buildingwebapps.blogspot.com/2012/01/passing-javascript-json-dictionary-to.html

2

Dies ist zu sehen, was ich versuchte. Spart viel Arbeit. 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"); 

Aktion Methode:

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

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

} 
+0

Nicht genau was ich wollte, weil es keinen Sinn macht, ein Objekt zu übergeben, wenn Sie das Wörterbuch selbst übergeben könnten, aber das funktioniert gut genug. Upvoted. :) –

Verwandte Themen