Как передать словарь в качестве параметра методу 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