ACTUALIZACIÓN
En base a la entrada de blog por Jeroen (ver su respuesta a continuación, con el enlace), y un destello del cerebro que había después de volver a revisar mi código, he actualizado el ExtendedJsonValueProviderFactory para que siempre cree correctamente un BackingStore para un diccionario de nivel superior enviado a través de JSON.
El código está disponible en GitHub en https://github.com/counsellorben/ASP.NET-MVC-JsonDictionaryBinding, y un ejemplo de trabajo está en http://oss.form.vu/json-dictionary-example/.
Mediante la eliminación de la corriente JsonValueProviderFactory
y sustituyendo uno que puede manejar la creación de diccionario, puede vincular a su diccionario. Primero, como señaló Keith, en su Javascript, asegúrese de ajustar su diccionario dentro de "filterItem", ya que este es el nombre de la variable de modelo en su acción de controlador, y para JSON, el nombre de la variable en la acción del controlador debe coincidir con el nombre del elemento Json que se devuelve. Además, al aprobar una clase, los elementos anidados deben coincidir con los nombres de las propiedades de la clase.
A continuación, cree una clase ExtendedJsonValueProviderFactory
, de la siguiente manera:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Globalization;
using System.IO;
using System.Web.Script.Serialization;
public sealed class ExtendedJsonValueProviderFactory : ValueProviderFactory
{
private void AddToBackingStore(Dictionary<string, object> backingStore, string prefix, object value)
{
IDictionary<string, object> d = value as IDictionary<string, object>;
if (d != null)
{
foreach (KeyValuePair<string, object> entry in d)
{
if (entry.Key.EndsWith("Dictionary", StringComparison.CurrentCulture))
CreateDictionary(backingStore, entry);
else
AddToBackingStore(backingStore, MakePropertyKey(prefix, entry.Key), entry.Value);
}
return;
}
IList l = value as IList;
if (l != null)
{
for (int i = 0; i < l.Count; i++)
{
AddToBackingStore(backingStore, MakeArrayKey(prefix, i), l[i]);
}
return;
}
// primitive
backingStore[prefix] = value;
}
private void CreateDictionary(Dictionary<string, object> backingStore, KeyValuePair<string, object> source)
{
var d = source.Value as IDictionary<string, object>;
var dictionary = new Dictionary<string, string>();
foreach (KeyValuePair<string, object> entry in d)
dictionary.Add(entry.Key, entry.Value.ToString());
AddToBackingStore(backingStore, source.Key, dictionary);
return;
}
private static object GetDeserializedObject(ControllerContext controllerContext)
{
if (!controllerContext.HttpContext.Request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase))
{
// not JSON request
return null;
}
StreamReader reader = new StreamReader(controllerContext.HttpContext.Request.InputStream);
string bodyText = reader.ReadToEnd();
if (String.IsNullOrEmpty(bodyText))
{
// no JSON data
return null;
}
JavaScriptSerializer serializer = new JavaScriptSerializer();
object jsonData = serializer.DeserializeObject(bodyText);
return jsonData;
}
public override IValueProvider GetValueProvider(ControllerContext controllerContext)
{
if (controllerContext == null)
{
throw new ArgumentNullException("controllerContext");
}
object jsonData = GetDeserializedObject(controllerContext);
if (jsonData == null)
{
return null;
}
Dictionary<string, object> backingStore = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
AddToBackingStore(backingStore, String.Empty, jsonData);
return new DictionaryValueProvider<object>(backingStore, CultureInfo.CurrentCulture);
}
private static string MakeArrayKey(string prefix, int index)
{
return prefix + "[" + index.ToString(CultureInfo.InvariantCulture) + "]";
}
private static string MakePropertyKey(string prefix, string propertyName)
{
return (String.IsNullOrEmpty(prefix)) ? propertyName : prefix + "." + propertyName;
}
}
Usted puede notar que esta clase es casi idéntica a la clase JsonValueProviderFactory estándar, a excepción de la extensión para construir una entrada en el DictionaryValueProvider de tipo Dictionary<string,string>
. También debe notar que, con el fin de ser procesado como un diccionario, un elemento debe tener un nombre que termina en "Diccionario" (y al mismo tiempo creo que esto es un olor código significativa, no puedo pensar en otra alternativa en este momento. .. Estoy abierto a sugerencias).
A continuación, añada lo siguiente a Application_Start
en Global.asax.cs
:
var j = ValueProviderFactories.Factories.FirstOrDefault(f => f.GetType().Equals(typeof(JsonValueProviderFactory)));
if (j != null)
ValueProviderFactories.Factories.Remove(j);
ValueProviderFactories.Factories.Add(new ExtendedJsonValueProviderFactory());
Esto eliminará la norma JsonValueProviderFactory, y reemplazarlo con nuestra clase extendida.
Paso final: disfrute de la bondad.
este hilo puede ayudar - http://stackoverflow.com/questions/4789481/post-an-array-of-objects-via-json-to-asp-net-mvc3 – Jason
Por lo que yo sé .Net no le gusta serializar/deserializar diccionarios. Puede que tenga que convertirlo en un IEnumerable> y luego usarlo en el constructor de un diccionario. –
Se deserializará/serializará 'Dictionary' only. –
Gabe