¿Cómo puedo deserializar JSON a un Diccionario simple<cadena, cadena> en ASP.NET?
asp.net-ajax asp.net-3.5 (19)
Tengo una lista 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 DESERIALIZAR EN OBJETOS .NET INTEGRAMENTE INTRODUCIDOS
Simplemente necesito un diccionario antiguo simple (de cadena, cadena) , o algo equivalente (tabla hash, diccionario (de cadena, objeto), cadena de la vieja escuela, infierno, una serie de cadenas en 2-D que 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 del cliente).
Al parecer, ninguna de estas bibliotecas JSON tiene esta capacidad obvia inmediata, ya que están totalmente centradas en la deserialización basada en la reflexión a través de contratos sólidos.
¿Algunas ideas?
Limitaciones:
- No quiero implementar mi propio analizador JSON
- Aún no puedo usar ASP.NET 4.0
- Preferiría mantenerse alejado de la antigua clase ASP.NET desaprobada para JSON
Acabo de implementar esto en RestSharp . Este post fue de gran ayuda 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<string, dynamic> response = jsonClient.Execute<JObject>(jsonRequest).Data.ToObject<Dictionary<string, dynamic>>();
Tenga en cuenta el tipo de JSON que está esperando: en mi caso, estaba recuperando un solo objeto con varias propiedades. En el enlace adjunto, el autor estaba recuperando una lista.
Agregué una verificación de 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 la cadena json a la función deserializeToDictionary que devolverá el Dictionary<string, object>
no muy tipificado.
private Dictionary<string, object> deserializeToDictionary(string jo)
{
var values = JsonConvert.DeserializeObject<Dictionary<string, object>>(jo);
var values2 = new Dictionary<string, object>();
foreach (KeyValuePair<string, object> 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<string, object>
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<string, object> values = deserializeToDictionary(responsestring);
}
Nota: la ciudad natal se deserializa aún más en un objeto Dictionary<string, object>
.
Basado en los comentarios above intente JsonConvert.DeserializeObject<Dictionary<string,dynamic>>(json)
var json = @"{""key1"":1,""key2"":""value2"", ""object1"":{""property1"":""value1"",""property2"":[2,3,4,5,6,7]}}";
var parsedObject = JsonConvert.DeserializeObject<Dictionary<string,dynamic>>(json);
Parece funcionar incluso para objetos complejos y listas.
Descubrí que .NET tiene una forma integrada de convertir la cadena JSON en un Dictionary<String, Object>
través del tipo System.Web.Script.Serialization.JavaScriptSerializer
en el ensamblaje 3.5 System.Web.Extensions
. Utilice el método DeserializeObject(String)
.
Me topé con esto cuando hice una publicación ajax (a través de jquery) del tipo de contenido ''application / json'' en un Método de página .net estático y vi que el método (que tenía un solo parámetro de tipo Object
) recibió mágicamente este Diccionario.
He agregado el código enviado por jSnake04 y Dasun aquí. He agregado código para crear listas de objetos desde instancias de JArray
. Tiene recursión en dos direcciones, pero como funciona en un modelo de árbol finito fijo, no hay riesgo de desbordamiento de pila a menos que los datos sean masivos.
/// <summary>
/// Deserialize the given JSON string data (<paramref name="data"/>) into a
/// dictionary.
/// </summary>
/// <param name="data">JSON string.</param>
/// <returns>Deserialized dictionary.</returns>
private IDictionary<string, object> DeserializeData(string data)
{
var values = JsonConvert.DeserializeObject<Dictionary<string, object>>(data);
return DeserializeData(values);
}
/// <summary>
/// Deserialize the given JSON object (<paramref name="data"/>) into a dictionary.
/// </summary>
/// <param name="data">JSON object.</param>
/// <returns>Deserialized dictionary.</returns>
private IDictionary<string, object> DeserializeData(JObject data)
{
var dict = data.ToObject<Dictionary<String, Object>>();
return DeserializeData(dict);
}
/// <summary>
/// Deserialize any elements of the given data dictionary (<paramref name="data"/>)
/// that are JSON object or JSON arrays into dictionaries or lists respectively.
/// </summary>
/// <param name="data">Data dictionary.</param>
/// <returns>Deserialized dictionary.</returns>
private IDictionary<string, object> DeserializeData(IDictionary<string, object> 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;
}
/// <summary>
/// Deserialize the given JSON array (<paramref name="data"/>) into a list.
/// </summary>
/// <param name="data">Data dictionary.</param>
/// <returns>Deserialized list.</returns>
private IList<Object> DeserializeData(JArray data)
{
var list = data.ToObject<List<Object>>();
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;
}
Intenté no usar ninguna implementación JSON externa, así que lo deserialicé de esta manera:
string json = "{/"id/":/"13/", /"value/": true}";
var serializer = new JavaScriptSerializer(); //using System.Web.Script.Serialization;
Dictionary<string, string> values = serializer.Deserialize<Dictionary<string, string>>(json);
Json.NET hace esto ...
string json = @"{""key1"":""value1"",""key2"":""value2""}";
var values = JsonConvert.DeserializeObject<Dictionary<string, string>>(json);
Más ejemplos: Serialización de colecciones con Json.NET
Mark Rendle publicó esto como un comentario . Quería publicarlo como una respuesta, ya que es la única solución que ha funcionado hasta ahora para devolver el éxito y los resultados de los códigos de error json de la respuesta de Google reCaptcha.
string jsonReponseString= wClient.DownloadString(requestUrl);
IDictionary<string, object> dict = new JavaScriptSerializer().DeserializeObject(jsonReponseString) as IDictionary<string, object>;
Gracias de nuevo, Mark!
Mi enfoque se deserializa directamente a IDictionary, sin JObject o ExpandObject en el medio. El código usa el convertidor, que básicamente se copia de la clase ExpandoObjectConverter que se encuentra en el código fuente de JSON.NET, pero que usa IDictionary en lugar de ExpandoObject.
Uso:
var settings = new JsonSerializerSettings()
{
Converters = { new DictionaryConverter() },
};
var result = JsonConvert.DeserializeObject<IDictionary<string, object>>(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<string, object>));
}
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<string, object>.");
}
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<string, object>: {0}", reader.TokenType));
}
}
private object ReadList(JsonReader reader)
{
List<object> list = new List<object>();
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<string, object>.");
}
private object ReadObject(JsonReader reader)
{
IDictionary<string, object> dictionary = new Dictionary<string, object>();
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<string, object>.");
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<string, object>.");
}
//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;
}
}
Para aquellos que buscan en internet y se topan con esta publicación, escribí una publicación de 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<dynamic>(json);
Console.WriteLine(table["id"]);
Console.WriteLine(table["value"]);
Parece que todas estas respuestas aquí simplemente asumen que puedes sacar esa pequeña cadena de un objeto más grande ... para las personas que buscan simplemente deserealizar un objeto grande con un diccionario de este tipo en algún lugar dentro del mapeo, y que están usando el Sistema de Tiempo de Ejecución System.Runtime.Serialization.Json
Sistema System.Runtime.Serialization.Json
DataContract, 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 casi perfecta: una clase personalizada IDataContractSurrogate
en la que implementas exactamente tus propios tipos. Pude expandirlo fácilmente.
Aunque hice un montón de cambios en ello. Como la fuente original ya no está disponible, publicaré la clase completa 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
{
/// <summary>
/// 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
/// </summary>
public class JsonSurrogate : IDataContractSurrogate
{
/// <summary>
/// Deserialize an object with added support for the types defined in this class.
/// </summary>
/// <typeparam name="T">Contract class</typeparam>
/// <param name="json">JSON String</param>
/// <param name="encoding">Text encoding</param>
/// <returns>The deserialized object of type T</returns>
public static T Deserialize<T>(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<Type, Type> KnownTypes =
new Dictionary<Type, Type>()
{
{typeof(Dictionary<String, String>), typeof(SSDictionary)},
{typeof(Dictionary<String, Boolean>), typeof(SBDictionary)}
};
#region Implemented surrogate dictionary classes
[Serializable]
public class SSDictionary : SurrogateDictionary<String>
{
public SSDictionary() : base() {}
protected SSDictionary (SerializationInfo info, StreamingContext context) : base(info, context) {}
}
[Serializable]
public class SBDictionary : SurrogateDictionary<Boolean>
{
public SBDictionary() : base() {}
protected SBDictionary (SerializationInfo info, StreamingContext context) : base(info, context) {}
}
#endregion
/// <summary>Small interface to easily extract the final value from the object.</summary>
public interface JsonSurrogateObject
{
Object DeserializedObject { get; }
}
/// <summary>
/// Class for deserializing any simple dictionary types with a string as key.
/// </summary>
/// <typeparam name="T">Any simple type that will be deserialized correctly.</typeparam>
[Serializable]
public abstract class SurrogateDictionary<T> : ISerializable, JsonSurrogateObject
{
public Object DeserializedObject { get { return dict; } }
private Dictionary<String, T> dict;
public SurrogateDictionary()
{
dict = new Dictionary<String, T>();
}
// deserialize
protected SurrogateDictionary(SerializationInfo info, StreamingContext context)
{
dict = new Dictionary<String, T>();
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]);
}
}
}
/// <summary>
/// Uses the KnownTypes dictionary to get the surrogate classes.
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
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();
}
/// <summary>
/// Gets the object out of the surrogate datacontract object. This function is the reason all surrogate objects need to implement the JsonSurrogateObject class.
/// </summary>
/// <param name="obj">Result of the deserialization</param>
/// <param name="targetType">Expected target type of the deserialization</param>
/// <returns></returns>
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<Type> customDataTypes)
{
throw new NotImplementedException();
}
public CodeTypeDeclaration ProcessImportedType(CodeTypeDeclaration typeDeclaration, CodeCompileUnit compileUnit)
{
throw new NotImplementedException();
}
#endregion
}
}
Para agregar nuevos tipos compatibles a la clase, solo necesita agregar su clase, asignarle los constructores y las funciones correctos (consulte SurrogateDictionary
para ver un ejemplo), asegúrese de que herede JsonSurrogateObject
y agregue su asignación de tipo al diccionario de KnownTypes
. El SurrogateDictionary incluido puede servir como base para cualquier tipo de Dictionary<String,T>
donde T es cualquier tipo que deserializa correctamente.
Llamarlo es realmente simple:
MyObjtype newObj = JsonSurrogate.Deserialize<MyObjtype>(jsonStr, encoding);
Tenga en cuenta que, por alguna razón, esto tiene problemas para usar cadenas de teclas que contienen espacios; simplemente no estaban presentes en la lista final. Podría ser simplemente contra las especificaciones de json y la API que estaba llamando fue mal implementada, claro; No se. De todos modos, resolví esto reemplazándolos con expresiones regulares por guiones bajos en los datos json en bruto y arreglando el diccionario después de la deserialización.
Si buscas un enfoque ligero, sin referencias agregadas, quizás este fragmento de código que acabo de escribir funcione (aunque no puedo garantizar el 100% de robustez).
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
public Dictionary<string, object> ParseJSON(string json)
{
int end;
return ParseJSON(json, 0, out end);
}
private Dictionary<string, object> ParseJSON(string json, int start, out int end)
{
Dictionary<string, object> dict = new Dictionary<string, object>();
bool escbegin = false;
bool escend = false;
bool inquotes = false;
string key = null;
int cend;
StringBuilder sb = new StringBuilder();
Dictionary<string, object> child = null;
List<object> 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<object>();
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 de OP # 1, pero técnicamente, no la escribiste, lo hice]
Solo necesitaba analizar un diccionario anidado , como
{
"x": {
"a": 1,
"b": 2,
"c": 3
}
}
donde JsonConvert.DeserializeObject
no ayuda. He encontrado el siguiente enfoque:
var dict = JObject.Parse(json).SelectToken("x").ToObject<Dictionary<string, int>>();
El SelectToken
permite excavar hasta el campo deseado. Incluso puede especificar una ruta como "xyz"
para avanzar más hacia el objeto 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 la cadena JSON a la función deserializeToDictionary; devolverá el Dictionary<string, object>
no sea muy tipificado.
Código antiguo
private Dictionary<string, object> deserializeToDictionary(string jo)
{
var values = JsonConvert.DeserializeObject<Dictionary<string, object>>(jo);
var values2 = new Dictionary<string, object>();
foreach (KeyValuePair<string, object> 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<string, object>
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<string, object> values = deserializeToDictionary(responsestring);
}
Nota: la ciudad natal se deseriliza aún más en un objeto
Dictionary<string, object>
.
Actualizar
Mi antigua respuesta funciona bien si no hay una matriz en la cadena JSON. Éste más se deserializa en un List<object>
si un elemento es una matriz.
Simplemente envíe una cadena JSON a la función deserializeToDictionaryOrList que devolverá el Dictionary<string, object>
o el List<object>
Dictionary<string, object>
no muy tipificado.
private static object deserializeToDictionaryOrList(string jo,bool isArray=false)
{
if (!isArray)
{
isArray = jo.Substring(0, 1) == "[";
}
if (!isArray)
{
var values = JsonConvert.DeserializeObject<Dictionary<string, object>>(jo);
var values2 = new Dictionary<string, object>();
foreach (KeyValuePair<string, object> 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<List<object>>(jo);
var values2 = new List<object>();
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;
}
}
Edición: esto funciona, pero la respuesta aceptada utilizando Json.NET es mucho más sencilla. Dejando este en caso de que alguien necesite un código solo BCL.
No es compatible con el marco de .NET de la caja. Una supervisión deslumbrante: no todos necesitan deserializarse en objetos con propiedades nombradas. Así que terminé rodando la mía:
<Serializable()> 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"]);
Lo siento por la mezcla de C # y VB.NET ...
Resulta molesto que si desea usar los modelos de carpetas predeterminados, parece que tendrá que usar valores de índice numérico como un formulario POST.
Vea el siguiente extracto de este artículo http://msdn.microsoft.com/en-us/magazine/hh781022.aspx :
Aunque es algo contraintuitivo, las solicitudes JSON tienen los mismos requisitos: también deben cumplir con la sintaxis de nomenclatura de formularios. Tomemos, por ejemplo, la carga JSON para la colección UnitPrice anterior. La sintaxis de matriz JSON pura para estos datos se representaría como:
[ { "Code": "USD", "Amount": 100.00 }, { "Code": "EUR", "Amount": 73.64 } ]
Sin embargo, los proveedores de valores predeterminados y las carpetas de modelos requieren que los datos se representen como una publicación de formulario JSON:
{ "UnitPrice[0].Code": "USD", "UnitPrice[0].Amount": 100.00, "UnitPrice[1].Code": "EUR", "UnitPrice[1].Amount": 73.64 }
El escenario complejo de colección de objetos es quizás uno de los escenarios más problemáticos que enfrentan los desarrolladores porque la sintaxis no es necesariamente evidente para todos los desarrolladores. Sin embargo, una vez que aprenda la sintaxis relativamente simple para publicar colecciones complejas, estos escenarios se vuelven mucho más fáciles de manejar.
Podrías usar Tiny-JSON
string json = "{/"key1/":/"value1/", /"key2/":/"value2/"}";
IDictionary<string, string> dict = Tiny.Json.Decode<Dictionary<string, string>>(json);
Un poco tarde para el juego, pero ninguna de las soluciones anteriores me apuntó en la dirección de una solución pura y simple .NET, no json.net. Así que aquí está, terminó siendo muy simple. Debajo de un ejemplo completo de cómo se hace con la serialización .NET Json estándar, el ejemplo tiene un diccionario tanto en el objeto raíz como en los objetos secundarios.
La bala dorada es este gato, analice la configuración como segundo parámetro del serializador:
DataContractJsonSerializerSettings settings =
new DataContractJsonSerializerSettings();
settings.UseSimpleDictionaryFormat = true;
Código completo a continuación:
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<string,Child> Children { get; set; }
}
[DataContract]
public class Child
{
[DataMember(Name = "name")]
public string Name { get; set; }
[DataMember(Name = "subs")]
public Dictionary<int, Sub> 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);
}
}
}
}
}
}
Yo sugeriría System.Runtime.Serialization.Json
que usar eso es parte de .NET 4.5.
[DataContract]
public class Foo
{
[DataMember(Name = "data")]
public Dictionary<string,string> Data { get; set; }
}
Entonces úsalo así:
var serializer = new DataContractJsonSerializer(typeof(List<Foo>));
var jsonParams = @"{""data"": [{""Key"":""foo"",""Value"":""bar""}] }";
var stream = new MemoryStream(Encoding.UTF8.GetBytes(jsonParams));
var obj = serializer.ReadObject(stream);
Console.WriteLine(obj);