UPDATE
Sulla base del post sul blog di Jeroen (vedere la sua risposta qui sotto, con il link), e un flash del cervello che avevo dopo la ri-esaminato il mio codice, ho aggiornato il ExtendedJsonValueProviderFactory in modo che crei sempre correttamente un BackingStore per un dizionario di livello superiore inviato tramite JSON.
Il codice è disponibile su GitHub allo https://github.com/counsellorben/ASP.NET-MVC-JsonDictionaryBinding e un esempio di lavoro è http://oss.form.vu/json-dictionary-example/.
Rimuovendo la corrente JsonValueProviderFactory
e sostituendo uno in grado di gestire la creazione del dizionario, è possibile associare il dizionario. Innanzitutto, come ha sottolineato Keith, nel tuo Javascript, assicurati di avvolgere il tuo dizionario all'interno di "filterItem", poiché questo è il nome della variabile del modello nell'azione del controller e, per JSON, il nome della variabile nell'azione del controller deve corrispondere al nome dell'elemento Json restituito. Inoltre, quando si passa una classe, qualsiasi elemento nidificato deve corrispondere ai nomi delle proprietà nella classe.
Successivamente, creare una classe ExtendedJsonValueProviderFactory
, come segue:
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;
}
}
Si può notare che questa classe è quasi identica alla classe JsonValueProviderFactory standard, ad eccezione per l'estensione di costruire un ingresso nel DictionaryValueProvider di tipo Dictionary<string,string>
. Si dovrebbe anche notare che, per essere elaborato come dizionario, un elemento deve avere un nome che termina con "Dizionario" (e mentre penso che questo sia un odore significativo del codice, non riesco a pensare ad un'altra alternativa in questo momento. .. Sono aperto a suggerimenti).
Avanti, aggiungere il seguente al Application_Start
in 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());
Questo eliminerà lo standard JsonValueProviderFactory, e sostituirlo con la nostra classe estesa.
Passaggio finale: godetevi la bontà.
questa discussione può aiutare - http://stackoverflow.com/questions/4789481/post-an-array-of-objects-via-json-to-asp-net-mvc3 – Jason
Per quanto ne so , .Net non ama serializzare/deserializzare i dizionari. Potrebbe essere necessario convertirlo in un oggetto IEnumerable> e quindi utilizzarlo nel costruttore di un dizionario. –
Deserializza/serializza solo 'Dictionary'. –
Gabe