2009-07-03 13 views
11

Używam jQuery do wykonania połączenia Ajax za pomocą postu HTTP w ASP.NET MVC. Chciałbym móc przekazać Słownik wartości.Jak przekazać słownik jako parametr do metody ActionResult z jQuery/Ajax?

Najbliższą rzeczą, o której mogłem pomyśleć, to przekazanie wielowymiarowej tablicy łańcuchów, ale wynikiem, który faktycznie przechodzi do metody ActionResult, jest jednowymiarowa tablica ciągów znaków zawierająca połączenie ciągów "klucz/wartość" "para.

Na przykład pierwsza pozycja w poniższej „wartości” tablicy zawiera wartość poniżej:

"id,200" 

Oto przykład z mojej metody ActionResult:

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

Oto przykład tego, jak ja” m wywołanie metody z jQuery:

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

Czy ktoś wie, jak przekazać słownik o bject z jQuery do metody ActionResult zamiast Array?

naprawdę chciałbym zdefiniować moją ActionResult tak:

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

sugestie?

UPDATE: Próbowałem przechodzącą w ciągu przecinkami wartości i to w zasadzie tylko uniemożliwia właściwie przeanalizować parę klucz/wartość przy użyciu ciąg parsowania.

przekazać to:

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

skutkuje to:

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

Nie sądzę, istnieje sposób, aby zrobić that.I może być źle, ale będzie to trywialne do analizowania danych przekazywanych w postaci ciąg tablic i sam stwórz słownik wewnątrz metody AddItems. –

+0

Nie jesteś pewien, jakie problemy z analizą składni będą powodowane przez przecinki w ramach wartości. –

+0

W końcu to wymyśliłem, dzięki wszystkim, którzy zgłosili sugestie! Dodałem ostateczne rozwiązanie jako odpowiedź poniżej. Zaznaczę to jako poprawną odpowiedź, jak tylko SO mi pozwoli. Dziękuję wszystkim! –

Odpowiedz

11

W końcu zorientowaliśmy się !! Dziękuję wszystkim za sugestie! W końcu doszedłem do wniosku, że najlepszym rozwiązaniem jest przekazanie JSON za pośrednictwem Http Post i użycie niestandardowego ModelBinder do konwersji JSON na słownik. Jedną rzeczą, którą zrobiłem w moim rozwiązaniu, jest stworzenie obiektu JsonDictionary, który dziedziczy po słowie, aby móc dołączyć niestandardowy modelBinder do typu JsonDictionary i nie spowoduje żadnych konfliktów w przyszłości, jeśli później użyję Dictionary jako parametru ActionResult. inny cel niż JSON.

Oto ostateczna metoda ActionResult:

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

I jQuery "$ .post" wezwanie:

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

Następnie JsonDictionaryModelBinder musi być zarejestrowany, dodałem to do sposobu Application_Start zasięgu Globalny.asax.cs:

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

I wreszcie oto JsonDictionaryMode Obiekt lBinder i obiekt JsonDictionary, który utworzyłem:

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

Jest to możliwe z niestandardowego modelu spoiw lub filtrów. Za kulisami - będziesz musiał to zrobić ręcznie (Request.Form, stwórz ciągi, stwórz słownik tralala), ale przynajmniej - twój kontroler będzie czysty, a kod będzie można ponownie wykorzystać do innych akcji.

1

Nie sądzę, że możliwe jest przekazanie słownika z jQuery/Ajax do metody ActionResult za pośrednictwem postu Http. Jedną z rzeczy, które wydawało mi się najłatwiejsze do wykonania, jest przekazanie obiektu JSON, a następnie przeanalizowanie go w Słowniku.

Oto zmodyfikowana wersja powyższego powołania „$ .post” z jQuery, który wysyła JSON jako pseudo-słownika:

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

Funkcja „Sys.Serialization.JavaScriptSerializer.serialize” jest metoda biblioteki JavaScript ASP.NET AJAX.

Oto zmodyfikowana wersja powyższej metody 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 
} 

myślę, że to sprawia, że ​​znacznie łatwiej jest jednostka testowa przekazując JSON, zamiast używania Collection formularza, aby wysłać/pobrać kolekcję klucz/pary wartości.Ponadto łatwiej jest pracować, niż zastanawiać się, jak zbudować niestandardowy moduł IModelBinder, a niestandardowy moduł IModelBinder może powodować problemy z innymi metodami ActionResult, gdy jest to jedyny sposób, który muszę wykonać.

+0

Chris, zobacz mój komentarz powyżej. Nadal uważam, że robisz to w trudny sposób. Nie jestem w 100% pewny, ale mam takie przejmujące uczucie, że jesteś. – griegs

0

DefaultModelBinder jest w stanie powiązać twój POST z tablicą lub słownikiem. Np

tablic:

public ActionResult AddItems(string[] values) 

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

, czyli

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

dla słowników

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

zmieniane:

Jeśli wartości są w formacie HTML, a następnie wejść w jQuery można zrobić coś takiego:

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

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

AKTUALIZACJA:

Zobacz również: Scott Hanselman's ComputerZen.com - ASP.NET Wire Format for Model Binding to Arrays, Lists, Collections, Dictionaries

+0

Próbowałem twojego przykładu ze Słownikiem, ale to nie kończy się zapełnianiem parametru "wartości"; po prostu staje się pustym słownikiem. –

+0

Czy wypróbowałeś słownik wartości zamiast Słownika . Sprawdź również, czy Twoje wartości [n] są zerowe i czy nieprzerwane. Sprawdź http://stackoverflow.com/questions/1031416/asp-net-mvc-model-binding-a-set-of-dynamically- generated-checkboxes-how-to/1031694#1031694 również –

0

To jest stary post, ale i tak nie mogę pomóc w kilku uwagach.

@ eu-ge-ne: "DefaultModelBinder jest w stanie powiązać twój POST z tablicą lub słownikiem." Prawdziwe, ale przynajmniej dla słowników, stwierdzam, że wymagana notacja formy jest raczej sprzeczna z intuicją.

@Chris: Wczoraj miałem dokładnie ten sam problem, próbując opublikować słownik JavaScript (JSON) w metodzie akcji kontrolera. Opracowałem zupełnie inny niestandardowy segregator modelowy, który przetwarza ogólne słowniki z różnymi argumentami typu. Przetestowałem go tylko w MVC 3 i prawdopodobnie miałem przewagę ulepszonego szkieletu.

Szczegółowe informacje o moich doświadczeniach i kodu źródłowego spoiwa zwyczaj modelu, proszę zobaczyć mojego blogu na http://buildingwebapps.blogspot.com/2012/01/passing-javascript-json-dictionary-to.html

2

To co próbowałem. Oszczędza dużo pracy. 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"); 

Metoda Działanie:

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

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

} 
+0

Nie dokładnie to, co chciałem, ponieważ nie ma sensu przekazywać obiektu, jeśli mógłbyś tylko przekazać słownik, ale to działa wystarczająco dobrze. Rewizja. :) –

Powiązane problemy