Как передать словарь в качестве параметра методу ActionResult из jQuery / Ajax?

Я использую jQuery для вызова Ajax с помощью HTTP-сообщения в ASP.NET MVC. Я хотел бы иметь возможность передать словарь ценностей.

самое близкое, что я мог придумать,-это передать многомерный массив строк, но результат, который фактически передается методу ActionResult, - это одномерный строковый массив, содержащий конкатенацию строк пары "ключ/значение".

например, первый элемент в приведенном ниже массиве "values" содержит ниже значения:

"id,200"

вот пример моего метода ActionResult:

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

вот пример того, как я вызываю метод из jQuery:

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

кто-нибудь знает, как передать объект словаря из jQuery в метод ActionResult вместо массива?

Я бы очень хотел определить свой ActionResult следующим образом:

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

какие предложения?

обновление: я попытался передать запятую в пределах значения, и это в основном просто делает невозможным фактически проанализировать пару ключ / значение с помощью синтаксического анализа строк.

пройти этот:

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

результаты в этом:

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

6 ответов


наконец-то я понял это!! Спасибо за предложения всем! Наконец, я понял, что лучшее решение-передать JSON через Http Post и использовать пользовательский ModelBinder для преобразования JSON в словарь. Одна вещь, которую я сделал в своем решении, - это создание объекта JsonDictionary, который наследуется от словаря, чтобы я мог присоединить пользовательский ModelBinder к типу JsonDictionary, и это не вызовет никаких конфликтов в будущем, если я использую словарь в качестве параметра ActionResult позже для другая цель, чем JSON.

вот окончательный метод ActionResult:

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

и jQuery "$.сообщение " call:

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

затем необходимо зарегистрировать JsonDictionaryModelBinder, я добавил Это в метод Application_Start в глобальном масштабе.асакс.cs:

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

и, наконец, вот объект 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);
    }
}

это то, что я пробовал. Экономит много работы. 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");

Метод Действия:

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

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

}

возможно с изготовленными на заказ модельными связывателями или фильтрами. За кулисами - вам все равно придется делать это вручную (запрос.Form, parse strings, create dictionary tralala), но как минимум - ваш контроллер будет чистым, а код будет многоразовым для других действий.


Я не думаю, что можно передать словарь из jQuery/Ajax в метод ActionResult через HTTP Post. Одна вещь, с которой я понял, кажется, легче всего работать, - это передать объект JSON, а затем разобрать его в словарь.

вот модифицированная версия вышеуказанного вызова"$.post " из jQuery, который отправляет JSON как псевдо-словарь:

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

"Sys.Сериализация.Класс javascriptserializer.функция сериализации-это метод в ASP.NET библиотека JavaScript AJAX.

вот модифицированная версия вышеуказанного метода 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
}

Я думаю, что это значительно упрощает модульный тест, передавая JSON, вместо использования коллекции форм для отправки/получения коллекции пар ключ/значение. Кроме того, проще работать, чем выяснять, как создать пользовательский IModelBinder, и пользовательский IModelBinder может вызвать проблемы с другими методами ActionResult, когда это единственный, который мне нужно сделать этот.


DefaultModelBinder может привязать ваш пост к массиву или словарю. Например:

для массивов:

public ActionResult AddItems(string[] values)

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

или:

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

для словарей:

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

обновление:

если ваши значения находятся во входах 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");

обновление:

также проверить это: Скотта Хансельмана ComputerZen.com - ASP.NET проволока Формат привязки модели к массивам, спискам, коллекциям, словарям


Это старый пост, но я не могу не иметь несколько замечаний в любом случае.

@eu-ge-ne: "DefaultModelBinder может привязать ваш пост к массиву или словарю.- Верно, но, по крайней мере, для словарей я нахожу требуемую форму обозначения довольно нелогичной.

@Chris: вчера у меня была точно такая же проблема при попытке опубликовать словарь JavaScript (JSON) в методе действия контроллера. Я разработал совершенно другую пользовательскую модель binder, которая обрабатывает generic словари с аргументами разных типов. Я тестировал его только в MVC 3 и, вероятно, имел преимущество улучшенной структуры.

для деталей моих опытов и исходного кода изготовленного на заказ модельного связывателя, пожалуйста см. мое сообщение блога на http://buildingwebapps.blogspot.com/2012/01/passing-javascript-json-dictionary-to.html