Как передать словарь в качестве параметра методу ActionResult из jQuery/Ajax?
Я использую jQuery для вызова Ajax, используя Http Post в 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");
Кто-нибудь знает, как передать объект Dictionary из jQuery в метод ActionResult вместо массива?
Мне бы очень хотелось определить мой ActionResult следующим образом:
public ActionResult AddItems(Dictionary<string, object> values)
{
// do something
}
Любые предложения?
UPDATE: Я пробовал прохождение в запятой внутри значения, и в основном это просто делает невозможным синтаксический анализ пары ключ/значение с помощью синтаксического анализа строк.
Передайте это:
values: [
["id", "200,300"],
["FirstName", "Chris"]
]
приводит к следующему:
values[0] = "id,200,300";
values[1] = "FirstName,Chris";
Ответы
Ответ 1
Наконец-то я это понял! Спасибо за предложения всем! Я, наконец, понял, что лучшим решением является передача JSON через Http Post и использование пользовательского ModelBinder для преобразования JSON в словарь. Одна вещь, которую я сделал в своем решении, - это создать объект JsonDictionary, который наследуется от словаря, чтобы я мог привязать пользовательский ModelBinder к типу JsonDictionary, и он не вызовет каких-либо конфликтов в будущем, если я буду использовать словарь как параметр ActionResult позже для различного назначения, чем JSON.
Здесь последний метод ActionResult:
public ActionResult AddItems([Bind(Include="values")] JsonDictionary values)
{
// do something
}
И вызов jQuery "$.post":
$.post("/Controller/AddItems",
{
values: Sys.Serialization.JavaScriptSerializer.serialize(
{
id: 200,
"name": "Chris"
}
)
},
function(data) { },
"json");
Затем необходимо зарегистрировать JsonDictionaryModelBinder, я добавил его в метод Application_Start в файле Global.asax.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);
}
}
Ответ 2
Это то, что я пробовал. Экономит много работы.
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; }
}
Ответ 3
Это возможно с помощью настраиваемых связующих или фильтров. За кулисами - вам все равно придется делать это вручную (Request.Form, анализировать строки, создавать словарь tralala), но по крайней мере - ваш контроллер будет чистым, а код будет повторно использоваться для других действий.
Ответ 4
Я не думаю, что можно передать в словаре из 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.Serialization.JavaScriptSerializer.serialize является методом JavaScript-библиотеки ASP.NET 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
}
Я думаю, что это облегчает Unit Test, передавая JSON вместо использования коллекции форм для отправки/получения коллекции пар ключ/значение. Кроме того, легче работать, чем выяснять, как создать пользовательский IModelBinder, и пользовательский IModelBinder может вызвать проблемы с другими методами ActionResult, когда это единственное, что мне нужно сделать.
Ответ 5
DefaultModelBinder может привязывать ваш POST к массиву или словарю. Например:
для массивов:
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");
ОБНОВЛЕНО:
Также проверьте это: Scott Hanselman ComputerZen.com - Формат проводки ASP.NET для привязки к массивам, спискам, коллекциям, словарям
Ответ 6
Это старый пост, но я все равно не могу сделать несколько замечаний.
@eu-ge-ne: "DefaultModelBinder может связывать ваш POST с массивом или словарем". Правда, но, по крайней мере, для словарей, я считаю, что требуемая формальная нотация довольно противоречива.
@Chris: Вчера у меня была такая же проблема при попытке опубликовать словарь JavaScript (JSON) в методе действий контроллера. Я разработал совершенно другое настраиваемое связующее устройство, которое обрабатывает общие словари с различными аргументами типа. Я тестировал его только в MVC 3 и, вероятно, имел преимущество в улучшенной структуре.
Подробные сведения о моем опыте и исходном коде привязки настраиваемой модели см. в моем сообщении в блоге http://buildingwebapps.blogspot.com/2012/01/passing-javascript-json-dictionary-to.html