¿Cómo puedo deserializar JSON en un simple diccionario en ASP.NET?

Tengo una lista de clave / valor simple en JSON que se envía de vuelta a ASP.NET a través de POST. Ejemplo:

{ "key1": "value1", "key2": "value2"} 

NO ESTOY TRATANDO DE DESESTAALIZAR OBJETOS .NET FUERTEMENTE TIPIFICADOS

Simplemente necesito un viejo diccionario simple (de String, String) o algún equivalente (tabla de hash, diccionario (Of String, Object), StringDictionary de la vieja escuela – hell, una matriz 2D de cadenas funcionaría para mí.

Puedo usar cualquier cosa disponible en ASP.NET 3.5, así como el popular Json.NET (que ya estoy usando para la serialización para el cliente).

Aparentemente, ninguna de estas bibliotecas JSON tiene esta capacidad obvia de golpear la frente: están totalmente enfocadas en la deserialización basada en la reflexión a través de contratos sólidos.

¿Algunas ideas?

Limitaciones

  1. No quiero implementar mi propio analizador JSON
  2. Aún no puedo usar ASP.NET 4.0
  3. Preferiría mantenerme alejado de la clase ASP.NET antigua y obsoleta para JSON

Json.NET hace esto …

 string json = @"{""key1"":""value1"",""key2"":""value2""}"; var values = JsonConvert.DeserializeObject>(json); 

Más ejemplos: serializar colecciones con Json.NET

Descubrí que .NET tiene una forma integrada de convertir la cadena JSON en un Dictionary través del tipo System.Web.Script.Serialization.JavaScriptSerializer en el ensamblado 3.5 System.Web.Extensions . Use el método DeserializeObject(String) .

Me encontré con esto al hacer una publicación ajax (a través de jquery) del tipo de contenido ‘application / json’ a un método de página .NET estático y vi que el método (que tenía un único parámetro de tipo Object ) recibía mágicamente este Dictionary.

Para aquellos que buscan en Internet y tropiezan con esta publicación, escribí una publicación en el blog sobre cómo usar la clase JavaScriptSerializer.

Leer más … http://procbits.com/2011/04/21/quick-json-serializationdeserialization-in-c/

Aquí hay un ejemplo:

 var json = "{\"id\":\"13\", \"value\": true}"; var jss = new JavaScriptSerializer(); var table = jss.Deserialize(json); Console.WriteLine(table["id"]); Console.WriteLine(table["value"]); 

Intenté no utilizar ninguna implementación JSON externa, así que me desialicé de esta manera:

 string json = "{\"id\":\"13\", \"value\": true}"; var serializer = new JavaScriptSerializer(); //using System.Web.Script.Serialization; Dictionary values = serializer.Deserialize>(json); 

Tuve el mismo problema, así que escribí esto yo mismo. Esta solución se diferencia de otras respuestas porque puede deserializarse en múltiples niveles.

Simplemente envíe una cadena JSON a la función deserializeToDictionary y devolverá el Dictionary no fuertemente tipado.

Código antiguo

 private Dictionary deserializeToDictionary(string jo) { var values = JsonConvert.DeserializeObject>(jo); var values2 = new Dictionary(); foreach (KeyValuePair d in values) { // if (d.Value.GetType().FullName.Contains("Newtonsoft.Json.Linq.JObject")) if (d.Value is JObject) { values2.Add(d.Key, deserializeToDictionary(d.Value.ToString())); } else { values2.Add(d.Key, d.Value); } } return values2; } 

Ej: Esto devolverá el Dictionary de una respuesta JSON de Facebook.

Prueba

 private void button1_Click(object sender, EventArgs e) { string responsestring = "{\"id\":\"721055828\",\"name\":\"Dasun Sameera Weerasinghe\",\"first_name\":\"Dasun\",\"middle_name\":\"Sameera\",\"last_name\":\"Weerasinghe\",\"username\":\"dasun\",\"gender\":\"male\",\"locale\":\"en_US\", hometown: {id: \"108388329191258\", name: \"Moratuwa, Sri Lanka\",}}"; Dictionary values = deserializeToDictionary(responsestring); } 

Nota: la ciudad natal se deseriliza adicionalmente en un objeto Dictionary .

Actualizar

Mi respuesta anterior funciona muy bien si no hay una matriz en la cadena JSON. Esta deserializa adicionalmente en una List si un elemento es una matriz.

Simplemente envíe una cadena JSON en la función deserializeToDictionaryOrList devolverá Dictionary object o List no fuertemente tipados.

 private static object deserializeToDictionaryOrList(string jo,bool isArray=false) { if (!isArray) { isArray = jo.Substring(0, 1) == "["; } if (!isArray) { var values = JsonConvert.DeserializeObject>(jo); var values2 = new Dictionary(); foreach (KeyValuePair d in values) { if (d.Value is JObject) { values2.Add(d.Key, deserializeToDictionary(d.Value.ToString())); } else if (d.Value is JArray) { values2.Add(d.Key, deserializeToDictionary(d.Value.ToString(), true)); } else { values2.Add(d.Key, d.Value); } } return values2; }else { var values = JsonConvert.DeserializeObject>(jo); var values2 = new List(); foreach (var d in values) { if (d is JObject) { values2.Add(deserializeToDictionary(d.ToString())); } else if (d is JArray) { values2.Add(deserializeToDictionary(d.ToString(), true)); } else { values2.Add(d); } } return values2; } } 

Si busca un enfoque liviano y sin referencias adicionales, tal vez este código que acabo de escribir funcione (aunque no puedo garantizar la solidez al 100%).

 using System; using System.Collections.Generic; using System.Text; using System.Text.RegularExpressions; public Dictionary ParseJSON(string json) { int end; return ParseJSON(json, 0, out end); } private Dictionary ParseJSON(string json, int start, out int end) { Dictionary dict = new Dictionary(); bool escbegin = false; bool escend = false; bool inquotes = false; string key = null; int cend; StringBuilder sb = new StringBuilder(); Dictionary child = null; List arraylist = null; Regex regex = new Regex(@"\\u([0-9a-z]{4})", RegexOptions.IgnoreCase); int autoKey = 0; for (int i = start; i < json.Length; i++) { char c = json[i]; if (c == '\\') escbegin = !escbegin; if (!escbegin) { if (c == '"') { inquotes = !inquotes; if (!inquotes && arraylist != null) { arraylist.Add(DecodeString(regex, sb.ToString())); sb.Length = 0; } continue; } if (!inquotes) { switch (c) { case '{': if (i != start) { child = ParseJSON(json, i, out cend); if (arraylist != null) arraylist.Add(child); else { dict.Add(key, child); key = null; } i = cend; } continue; case '}': end = i; if (key != null) { if (arraylist != null) dict.Add(key, arraylist); else dict.Add(key, DecodeString(regex, sb.ToString())); } return dict; case '[': arraylist = new List(); continue; case ']': if (key == null) { key = "array" + autoKey.ToString(); autoKey++; } if (arraylist != null && sb.Length > 0) { arraylist.Add(sb.ToString()); sb.Length = 0; } dict.Add(key, arraylist); arraylist = null; key = null; continue; case ',': if (arraylist == null && key != null) { dict.Add(key, DecodeString(regex, sb.ToString())); key = null; sb.Length = 0; } if (arraylist != null && sb.Length > 0) { arraylist.Add(sb.ToString()); sb.Length = 0; } continue; case ':': key = DecodeString(regex, sb.ToString()); sb.Length = 0; continue; } } } sb.Append(c); if (escend) escbegin = false; if (escbegin) escend = true; else escend = false; } end = json.Length - 1; return dict; //theoretically shouldn't ever get here } private string DecodeString(Regex regex, string str) { return Regex.Unescape(regex.Replace(str, match => char.ConvertFromUtf32(Int32.Parse(match.Groups[1].Value, System.Globalization.NumberStyles.HexNumber)))); } 

[Me doy cuenta de que esto viola la Limitación OP # 1, pero técnicamente, no lo escribiste, lo hice]

Solo necesitaba analizar un diccionario nested , como

 { "x": { "a": 1, "b": 2, "c": 3 } } 

donde JsonConvert.DeserializeObject no ayuda. Encontré el siguiente enfoque:

 var dict = JObject.Parse(json).SelectToken("x").ToObject>(); 

SelectToken te permite buscar el campo deseado. Incluso puede especificar una ruta como "xyz" para avanzar hacia el objeto JSON.

Editar: Esto funciona, pero la respuesta aceptada usando Json.NET es mucho más directa. Dejando este en caso de que alguien necesite código BCL-only.

No es compatible con el marco .NET fuera de la caja. Un deslumbrante descuido: no todos necesitan deserializarse en objetos con propiedades nombradas. Así que terminé haciendo mi propia cuenta:

  Public Class StringStringDictionary Implements ISerializable Public dict As System.Collections.Generic.Dictionary(Of String, String) Public Sub New() dict = New System.Collections.Generic.Dictionary(Of String, String) End Sub Protected Sub New(info As SerializationInfo, _ context As StreamingContext) dict = New System.Collections.Generic.Dictionary(Of String, String) For Each entry As SerializationEntry In info dict.Add(entry.Name, DirectCast(entry.Value, String)) Next End Sub Public Sub GetObjectData(info As SerializationInfo, context As StreamingContext) Implements ISerializable.GetObjectData For Each key As String in dict.Keys info.AddValue(key, dict.Item(key)) Next End Sub End Class 

Llamado con:

 string MyJsonString = "{ \"key1\": \"value1\", \"key2\": \"value2\"}"; System.Runtime.Serialization.Json.DataContractJsonSerializer dcjs = new System.Runtime.Serialization.Json.DataContractJsonSerializer( typeof(StringStringDictionary)); System.IO.MemoryStream ms = new System.IO.MemoryStream(Encoding.UTF8.GetBytes(MyJsonString)); StringStringDictionary myfields = (StringStringDictionary)dcjs.ReadObject(ms); Response.Write("Value of key2: " + myfields.dict["key2"]); 

Perdón por la mezcla de C # y VB.NET …

Agregué un cheque para valores nulos en el JSON a la otra respuesta

Tuve el mismo problema, así que escribí esto yo mismo. Esta solución se diferencia de otras respuestas porque puede deserializarse en múltiples niveles.

Simplemente envíe cadena json en la función deserializeToDictionary devolverá el Dictionary no fuertemente tipado.

 private Dictionary deserializeToDictionary(string jo) { var values = JsonConvert.DeserializeObject>(jo); var values2 = new Dictionary(); foreach (KeyValuePair d in values) { if (d.Value != null && d.Value.GetType().FullName.Contains("Newtonsoft.Json.Linq.JObject")) { values2.Add(d.Key, deserializeToDictionary(d.Value.ToString())); } else { values2.Add(d.Key, d.Value); } } return values2; } 

Ej: Esto devolverá el Dictionary de una respuesta JSON de Facebook.

 private void button1_Click(object sender, EventArgs e) { string responsestring = "{\"id\":\"721055828\",\"name\":\"Dasun Sameera Weerasinghe\",\"first_name\":\"Dasun\",\"middle_name\":\"Sameera\",\"last_name\":\"Weerasinghe\",\"username\":\"dasun\",\"gender\":\"male\",\"locale\":\"en_US\", hometown: {id: \"108388329191258\", name: \"Moratuwa, Sri Lanka\",}}"; Dictionary values = deserializeToDictionary(responsestring); } 

Nota: la ciudad natal se deserializa aún más en un objeto Dictionary .

He agregado el código enviado por jSnake04 y Dasun aquí. He agregado código para crear listas de objetos de instancias de JArray . Tiene recursión bidireccional, pero como está funcionando en un modelo de árbol fijo y finito, no hay riesgo de desbordamiento de stack a menos que los datos sean masivos.

 ///  /// Deserialize the given JSON string data () into a /// dictionary. ///  /// JSON string. /// Deserialized dictionary. private IDictionary DeserializeData(string data) { var values = JsonConvert.DeserializeObject>(data); return DeserializeData(values); } ///  /// Deserialize the given JSON object () into a dictionary. ///  /// JSON object. /// Deserialized dictionary. private IDictionary DeserializeData(JObject data) { var dict = data.ToObject>(); return DeserializeData(dict); } ///  /// Deserialize any elements of the given data dictionary () /// that are JSON object or JSON arrays into dictionaries or lists respectively. ///  /// Data dictionary. /// Deserialized dictionary. private IDictionary DeserializeData(IDictionary data) { foreach (var key in data.Keys.ToArray()) { var value = data[key]; if (value is JObject) data[key] = DeserializeData(value as JObject); if (value is JArray) data[key] = DeserializeData(value as JArray); } return data; } ///  /// Deserialize the given JSON array () into a list. ///  /// Data dictionary. /// Deserialized list. private IList DeserializeData(JArray data) { var list = data.ToObject>(); for (int i = 0; i < list.Count; i++) { var value = list[i]; if (value is JObject) list[i] = DeserializeData(value as JObject); if (value is JArray) list[i] = DeserializeData(value as JArray); } return list; } 

Mark Rendle publicó esto como un comentario , quería publicarlo como una respuesta, ya que es la única solución que ha funcionado hasta el momento para devolver el éxito y los códigos de error de los resultados json de la respuesta de Google recaptcha.

 string jsonReponseString= wClient.DownloadString(requestUrl); IDictionary dict = new JavaScriptSerializer().DeserializeObject(jsonReponseString) as IDictionary; 

Gracias de nuevo, Mark!

Parece que todas estas respuestas aquí solo suponen que puede obtener esa pequeña cadena de un objeto más grande … para las personas que buscan simplemente deserealizar un objeto grande con un diccionario en algún lugar dentro de la asignación, y que están usando System.Runtime.Serialization.Json DataContract system, aquí hay una solución:

Una respuesta en gis.stackexchange.com tenía este enlace interesante . Tuve que recuperarlo con archive.org, pero ofrece una solución bastante perfecta: una clase IDataContractSurrogate personalizada en la que implementas exactamente tus propios tipos. Pude expandirlo fácilmente.

Sin embargo, hice un montón de cambios. Como la fuente original ya no está disponible, publicaré toda la clase aquí:

 using System; using System.CodeDom; using System.Collections.Generic; using System.Collections.ObjectModel; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.Serialization; using System.Runtime.Serialization.Json; using System.Text; namespace JsonTools { ///  /// Allows using Dictionary<String,String> and Dictionary<String,Boolean> types, and any others you'd like to add. /// Source: https://web.archive.org/web/20100317222656/my6solutions.com/post/2009/06/30/DataContractSerializer-DataContractJsonSerializer-JavaScriptSerializer-XmlSerializer-for-serialization.aspx ///  public class JsonSurrogate : IDataContractSurrogate { ///  /// Deserialize an object with added support for the types defined in this class. ///  /// Contract class /// JSON String /// Text encoding /// The deserialized object of type T public static T Deserialize(String json, Encoding encoding) { if (encoding == null) encoding = new UTF8Encoding(false); DataContractJsonSerializer deserializer = new DataContractJsonSerializer( typeof(T), new Type[0], int.MaxValue, true, new JsonSurrogate(), false); using (MemoryStream stream = new MemoryStream(encoding.GetBytes(json))) { T result = (T)deserializer.ReadObject(stream); return result; } } // make sure all values in this are classes implementing JsonSurrogateObject. private static Dictionary KnownTypes = new Dictionary() { {typeof(Dictionary), typeof(SSDictionary)}, {typeof(Dictionary), typeof(SBDictionary)} }; #region Implemented surrogate dictionary classes [Serializable] public class SSDictionary : SurrogateDictionary { public SSDictionary() : base() {} protected SSDictionary (SerializationInfo info, StreamingContext context) : base(info, context) {} } [Serializable] public class SBDictionary : SurrogateDictionary { public SBDictionary() : base() {} protected SBDictionary (SerializationInfo info, StreamingContext context) : base(info, context) {} } #endregion /// Small interface to easily extract the final value from the object. public interface JsonSurrogateObject { Object DeserializedObject { get; } } ///  /// Class for deserializing any simple dictionary types with a string as key. ///  /// Any simple type that will be deserialized correctly. [Serializable] public abstract class SurrogateDictionary : ISerializable, JsonSurrogateObject { public Object DeserializedObject { get { return dict; } } private Dictionary dict; public SurrogateDictionary() { dict = new Dictionary(); } // deserialize protected SurrogateDictionary(SerializationInfo info, StreamingContext context) { dict = new Dictionary(); foreach (SerializationEntry entry in info) { // This cast will only work for base types, of course. dict.Add(entry.Name, (T)entry.Value); } } // serialize public void GetObjectData(SerializationInfo info, StreamingContext context) { foreach (String key in dict.Keys) { info.AddValue(key, dict[key]); } } } ///  /// Uses the KnownTypes dictionary to get the surrogate classes. ///  ///  ///  public Type GetDataContractType(Type type) { Type returnType; if (KnownTypes.TryGetValue(type, out returnType)) { return returnType; } return type; } public object GetObjectToSerialize(object obj, Type targetType) { throw new NotImplementedException(); } ///  /// Gets the object out of the surrogate datacontract object. This function is the reason all surrogate objects need to implement the JsonSurrogateObject class. ///  /// Result of the deserialization /// Expected target type of the deserialization ///  public object GetDeserializedObject(object obj, Type targetType) { if (obj is JsonSurrogateObject) { return ((JsonSurrogateObject)obj).DeserializedObject; } return obj; } public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData) { return null; } #region not implemented public object GetCustomDataToExport(MemberInfo memberInfo, Type dataContractType) { throw new NotImplementedException(); } public object GetCustomDataToExport(Type clrType, Type dataContractType) { throw new NotImplementedException(); } public void GetKnownCustomDataTypes(Collection customDataTypes) { throw new NotImplementedException(); } public CodeTypeDeclaration ProcessImportedType(CodeTypeDeclaration typeDeclaration, CodeCompileUnit compileUnit) { throw new NotImplementedException(); } #endregion } } 

Para agregar nuevos tipos admitidos a la clase, solo necesita agregar su clase, darle los constructores y las funciones correctas (mire SurrogateDictionary para ver un ejemplo), asegúrese de que hereda JsonSurrogateObject y agregue su asignación de tipos al diccionario KnownTypes . El SurrogateDictionary incluido puede servir como base para cualquier tipo de Dictionary donde T es cualquier tipo que se deserialice correctamente.

Llamarlo es realmente simple:

 MyObjtype newObj = JsonSurrogate.Deserialize(jsonStr, encoding); 

Tenga en cuenta que, por alguna razón, esta cosa tiene problemas para utilizar cadenas clave que contienen espacios; simplemente no estaban presentes en la lista final. Podría ser simplemente contra especificaciones de json y la API a la que llamaba estaba mal implementada, fíjate; No se. De todos modos, resolví esto regex-reemplazándolos con guiones bajos en los datos raw json y reparando el diccionario después de la deserialización.

Basado en los comentarios anteriores, pruebe JsonConvert.DeserializeObject>(json)

 var json = @"{""key1"":1,""key2"":""value2"", ""object1"":{""property1"":""value1"",""property2"":[2,3,4,5,6,7]}}"; var parsedObject = JsonConvert.DeserializeObject>(json); 

parece funcionar incluso para objetos complejos y listas.

Acabo de implementar esto en RestSharp . Esta publicación fue útil para mí.

Además del código en el enlace, aquí está mi código. Ahora obtengo un Dictionary de resultados cuando hago algo como esto:

 var jsonClient = new RestClient(url.Host); jsonClient.AddHandler("application/json", new DynamicJsonDeserializer()); var jsonRequest = new RestRequest(url.Query, Method.GET); Dictionary response = jsonClient.Execute(jsonRequest).Data.ToObject>(); 

Tenga en cuenta el tipo de JSON que está esperando, en mi caso, estaba recuperando un único objeto con varias propiedades. En el enlace adjunto, el autor estaba recuperando una lista.

Mi enfoque se deserializa directamente a IDictionary, sin JObject o ExpandObject en el medio. El código usa convertidor, que básicamente se copia de la clase ExpandoObjectConverter que se encuentra en el código fuente JSON.NET, pero usa IDictionary en lugar de ExpandoObject.

Uso:

 var settings = new JsonSerializerSettings() { Converters = { new DictionaryConverter() }, }; var result = JsonConvert.DeserializeObject>(json, settings); 

Código:

 // based on ExpandoObjectConverter, but using arrays instead of IList, to behave similar to System.Web.Script.Serialization.JavaScriptSerializer public class DictionaryConverter : JsonConverter { public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { return ReadValue(reader); } public override bool CanConvert(Type objectType) { return (objectType == typeof(IDictionary)); } public override bool CanWrite { get { return false; } } private object ReadValue(JsonReader reader) { while (reader.TokenType == JsonToken.Comment) { if (!reader.Read()) throw JsonSerializationExceptionCreate(reader, "Unexpected end when reading IDictionary."); } switch (reader.TokenType) { case JsonToken.StartObject: return ReadObject(reader); case JsonToken.StartArray: return ReadList(reader); default: if (IsPrimitiveToken(reader.TokenType)) return reader.Value; throw JsonSerializationExceptionCreate(reader, string.Format(CultureInfo.InvariantCulture, "Unexpected token when converting IDictionary: {0}", reader.TokenType)); } } private object ReadList(JsonReader reader) { List list = new List(); while (reader.Read()) { switch (reader.TokenType) { case JsonToken.Comment: break; default: object v = ReadValue(reader); list.Add(v); break; case JsonToken.EndArray: return list; } } throw JsonSerializationExceptionCreate(reader, "Unexpected end when reading IDictionary."); } private object ReadObject(JsonReader reader) { IDictionary dictionary = new Dictionary(); while (reader.Read()) { switch (reader.TokenType) { case JsonToken.PropertyName: string propertyName = reader.Value.ToString(); if (!reader.Read()) throw JsonSerializationExceptionCreate(reader, "Unexpected end when reading IDictionary."); object v = ReadValue(reader); dictionary[propertyName] = v; break; case JsonToken.Comment: break; case JsonToken.EndObject: return dictionary; } } throw JsonSerializationExceptionCreate(reader, "Unexpected end when reading IDictionary."); } //based on internal Newtonsoft.Json.JsonReader.IsPrimitiveToken internal static bool IsPrimitiveToken(JsonToken token) { switch (token) { case JsonToken.Integer: case JsonToken.Float: case JsonToken.String: case JsonToken.Boolean: case JsonToken.Undefined: case JsonToken.Null: case JsonToken.Date: case JsonToken.Bytes: return true; default: return false; } } // based on internal Newtonsoft.Json.JsonSerializationException.Create private static JsonSerializationException JsonSerializationExceptionCreate(JsonReader reader, string message, Exception ex = null) { return JsonSerializationExceptionCreate(reader as IJsonLineInfo, reader.Path, message, ex); } // based on internal Newtonsoft.Json.JsonSerializationException.Create private static JsonSerializationException JsonSerializationExceptionCreate(IJsonLineInfo lineInfo, string path, string message, Exception ex) { message = JsonPositionFormatMessage(lineInfo, path, message); return new JsonSerializationException(message, ex); } // based on internal Newtonsoft.Json.JsonPosition.FormatMessage internal static string JsonPositionFormatMessage(IJsonLineInfo lineInfo, string path, string message) { if (!message.EndsWith(Environment.NewLine)) { message = message.Trim(); if (!message.EndsWith(".", StringComparison.Ordinal)) message += "."; message += " "; } message += string.Format(CultureInfo.InvariantCulture, "Path '{0}'", path); if (lineInfo != null && lineInfo.HasLineInfo()) message += string.Format(CultureInfo.InvariantCulture, ", line {0}, position {1}", lineInfo.LineNumber, lineInfo.LinePosition); message += "."; return message; } } 

Annoyingly enough, if you want to use the default model binders, it looks like you will have to use numerical index values like a form POST.

See the following excerpt from this article http://msdn.microsoft.com/en-us/magazine/hh781022.aspx :

Though it’s somewhat counterintuitive, JSON requests have the same requirements—they, too, must adhere to the form post naming syntax. Take, for example, the JSON payload for the previous UnitPrice collection. The pure JSON array syntax for this data would be represented as:

 [ { "Code": "USD", "Amount": 100.00 }, { "Code": "EUR", "Amount": 73.64 } ] 

However, the default value providers and model binders require the data to be represented as a JSON form post:

 { "UnitPrice[0].Code": "USD", "UnitPrice[0].Amount": 100.00, "UnitPrice[1].Code": "EUR", "UnitPrice[1].Amount": 73.64 } 

The complex object collection scenario is perhaps one of the most widely problematic scenarios that developers run into because the syntax isn’t necessarily evident to all developers. However, once you learn the relatively simple syntax for posting complex collections, these scenarios become much easier to deal with.

You could use Tiny-JSON

 string json = "{\"key1\":\"value1\", \"key2\":\"value2\"}"; IDictionary dict = Tiny.Json.Decode>(json); 

A bit late to the game, but non of the above solutions pointed me in the direction of a pure and simple .NET, no json.net solution. So here it is, ended up being very simple. Below a full running example of how it is done with standard .NET Json serialization, the example has dictionary both in the root object and in the child objects.

The golden bullet is this cat, parse the settings as second parameter to the serializer:

 DataContractJsonSerializerSettings settings = new DataContractJsonSerializerSettings(); settings.UseSimpleDictionaryFormat = true; 

Full code below:

 using System; using System.Collections.Generic; using System.Runtime.Serialization; using System.Runtime.Serialization.Json; namespace Kipon.dk { public class JsonTest { public const string EXAMPLE = @"{ ""id"": ""some id"", ""children"": { ""f1"": { ""name"": ""name 1"", ""subs"": { ""1"": { ""name"": ""first sub"" }, ""2"": { ""name"": ""second sub"" } } }, ""f2"": { ""name"": ""name 2"", ""subs"": { ""37"": { ""name"": ""is 37 in key""} } } } } "; [DataContract] public class Root { [DataMember(Name ="id")] public string Id { get; set; } [DataMember(Name = "children")] public Dictionary Children { get; set; } } [DataContract] public class Child { [DataMember(Name = "name")] public string Name { get; set; } [DataMember(Name = "subs")] public Dictionary Subs { get; set; } } [DataContract] public class Sub { [DataMember(Name = "name")] public string Name { get; set; } } public static void Test() { var array = System.Text.Encoding.UTF8.GetBytes(EXAMPLE); using (var mem = new System.IO.MemoryStream(array)) { mem.Seek(0, System.IO.SeekOrigin.Begin); DataContractJsonSerializerSettings settings = new DataContractJsonSerializerSettings(); settings.UseSimpleDictionaryFormat = true; var ser = new DataContractJsonSerializer(typeof(Root), settings); var data = (Root)ser.ReadObject(mem); Console.WriteLine(data.Id); foreach (var childKey in data.Children.Keys) { var child = data.Children[childKey]; Console.WriteLine(" Child: " + childKey + " " + child.Name); foreach (var subKey in child.Subs.Keys) { var sub = child.Subs[subKey]; Console.WriteLine(" Sub: " + subKey + " " + sub.Name); } } } } } } 

I would suggest using System.Runtime.Serialization.Json that is part of .NET 4.5.

 [DataContract] public class Foo { [DataMember(Name = "data")] public Dictionary Data { get; set; } } 

Then use it like this:

 var serializer = new DataContractJsonSerializer(typeof(List)); var jsonParams = @"{""data"": [{""Key"":""foo"",""Value"":""bar""}] }"; var stream = new MemoryStream(Encoding.UTF8.GetBytes(jsonParams)); var obj = serializer.ReadObject(stream); Console.WriteLine(obj);