Comment puis-je desérialiser JSON à un simple Dictionnaire en ASP.NET je ne sais pas.

j'ai une clé simple/liste de valeurs dans JSON étant envoyé à ASP.NET par la poste. Exemple:

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

JE N'ESSAIE PAS DE DESÉRIALISER EN OBJETS .NET FORTEMENT TYPÉS

j'ai simplement besoin d'un bon vieux Dictionnaire(String, String) , ou l'équivalent (table de hachage, Dictionnaire(String, Object), de la vieille école StringDictionary--l'enfer, un 2-D tableau de chaînes de caractères pourrait fonctionner pour moi.

je peux utiliser tout ce qui est disponible ASP.NET 3.5, ainsi que le populaire Json.NET (que j'utilise déjà pour la sérialisation en le client).

apparemment aucune de ces bibliothèques JSON n'a cette capacité évidente de sortie de la boîte-elles sont totalement focalisées sur la désérialisation basée sur la réflexion via des contrats forts.

des idées?

Limitations:

  1. je ne veux pas mettre en œuvre mon propre parser JSON
  2. ne peut pas utiliser ASP.NET 4.0 pourtant
  3. préférerait rester loin de l'ancien, déprécié ASP.NET classe pour JSON
567
demandé sur richardtallent 2009-07-30 20:28:00

19 réponses

Json.NET fait ça...

string json = @"{""key1"":""value1"",""key2"":""value2""}";

var values = JsonConvert.DeserializeObject<Dictionary<string, string>>(json);

autres exemples: sérialiser les Collections avec Json.NET

750
répondu James Newton-King 2017-07-28 16:32:50

j'ai découvert.net a un construit en manière pour mouler la chaîne JSON dans un Dictionary<String, Object> via le type System.Web.Script.Serialization.JavaScriptSerializer dans l'ensemble 3.5 System.Web.Extensions . Utilisez la méthode DeserializeObject(String) .

je suis tombé sur cela en faisant un post ajax (via jquery) de type de contenu 'application/json' à une méthode statique .net Page et j'ai vu que la méthode (qui avait un seul paramètre de type Object ) reçu par magie ce dictionnaire.

93
répondu Crispy 2012-02-11 06:55:51

pour ceux qui cherchent sur internet et en trébuchant sur ce post, j'ai écrit un billet de blog sur la façon d'utiliser la classe JavaScriptSerializer.

lire la suite... http://procbits.com/2011/04/21/quick-json-serializationdeserialization-in-c /

voici un exemple:

var json = "{\"id\":\"13\", \"value\": true}";
var jss = new JavaScriptSerializer();
var table = jss.Deserialize<dynamic>(json);
Console.WriteLine(table["id"]);
Console.WriteLine(table["value"]);
51
répondu JP Richardson 2011-05-11 14:28:55

a essayé de ne pas utiliser d'implémentation JSON externe donc j'ai désérialisé comme ceci:

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);
38
répondu PvH 2012-01-12 11:06:42

j'ai eu le même problème, donc j'ai écrit ceci moi-même. Cette solution est différenciée des autres réponses parce qu'elle peut se désérialiser à plusieurs niveaux.

Juste envoyer chaîne JSON dans deserializeToDictionary de la fonction, il sera de retour non fortement typées Dictionary<string, object> objet.

ancien code

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;
}

Ex: ceci retournera Dictionary<string, object> objet D'une réponse JSON Facebook.

Test

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);
}

Remarque: ville natale de plus amples deserilize dans un Dictionary<string, object> objet.

mise à Jour

mon ancienne réponse fonctionne très bien s'il n'y a pas de tableau sur la chaîne JSON. Celle-ci se désérialise à nouveau en List<object> si un élément est un tableau.

il suffit d'envoyer une chaîne JSON dans deserializeToDictionaryOrList de la fonction, il sera de retour non fortement typées Dictionary<string, object> objet ou List<object> .

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;
    }
}
28
répondu Dasun 2018-01-05 08:12:13

si vous êtes après une approche légère, sans-ajout-références genre d'approche, peut-être que ce peu de code que je viens d'écrire fonctionnera (Je ne peux pas 100% garantir la robustesse cependant).

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))));
}

[je me rends compte que cela porte atteinte à l'OP Limitation #1, mais techniquement, vous n'avez pas l'écrire, je l'ai fait]

16
répondu dexy 2012-11-06 04:33:14

j'ai juste besoin d'analyser une imbriqués dictionnaire comme

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

JsonConvert.DeserializeObject n'aide pas. J'ai trouvé l'approche suivante:

var dict = JObject.Parse(json).SelectToken("x").ToObject<Dictionary<string, int>>();

le SelectToken vous permet de creuser jusqu'au champ désiré. Vous pouvez même spécifier un chemin comme "x.y.z" pour descendre plus loin dans l'objet JSON.

9
répondu Falko 2016-08-11 18:46:04

Edit: cela fonctionne, mais la réponse acceptée en utilisant Json.NET c'est beaucoup plus simple. En laissant celui-ci au cas où quelqu'un aurait besoin d'un code uniquement BCL.

il n'est pas supporté par le .net framework out of the box. Un oubli flagrant – tout le monde n'a pas besoin de se desérialiser en objets avec des propriétés nommées. Alors j'ai fini par rouler le mien:

<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

appelé avec:

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"]);

désolé pour le mélange de C# et de VB.NET ...

5
répondu richardtallent 2013-04-30 18:38:48

j'ai ajouté une vérification des valeurs nulles dans le JSON à l'autre réponse

j'ai eu le même problème donc j'ai écrit ceci moi-même. Cette solution est différenciée des autres réponses parce qu'elle peut se désérialiser en plusieurs niveaux.

envoyez JSON string à deserializetodiciary fonction it retournera l'objet non fortement dactylographié Dictionary<string, object> .

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;
}

Ex: ceci retournera Dictionary<string, object> objet D'un Facebook Réponse de JSON.

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);
}

Note: hometown deserialize further into a Dictionary<string, object> object.

4
répondu jSnake04 2015-01-13 20:11:16

j'ai ajouté sur le code soumis par jSnake04 et Dasun ici. J'ai ajouté du code pour créer des listes d'objets à partir d'instances JArray . Il a une récursion bidirectionnelle, mais comme il fonctionne sur un modèle d'arbre fixe, fini, il n'y a aucun risque de débordement de la pile à moins que les données soient massives.

/// <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;
}
3
répondu Jordan 2015-03-03 18:56:15

Mark Rendle a posté ce comme un commentaire , je voulais le poster comme une réponse car c'est la seule solution qui a fonctionné jusqu'à présent pour retourner le succès et les résultats des codes d'erreur json de la réponse de reCaptcha Google.

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

Merci encore, Mark!

3
répondu Bryan 2018-05-14 16:42:47

il semble que toutes ces réponses ici juste supposer que vous pouvez obtenir cette petite corde d'un plus grand objet... pour les personnes qui cherchent à tout simplement deserealize un grand objet avec un tel dictionnaire quelque part à l'intérieur de la cartographie, et qui utilisent le système System.Runtime.Serialization.Json DataContract, voici une solution:

une réponse sur gis.stackexchange.com avait ce lien intéressant . J'ai dû le récupérer avec archive.org mais il offre une solution assez parfaite: une classe IDataContractSurrogate personnalisée dans laquelle vous mettez en œuvre exactement vos propres types. J'ai été en mesure d'étendre facilement.

j'ai fait un tas de changements, cependant. Puisque la source originale n'est plus disponible, je posterai toute la classe ici:

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&lt;String,String&gt; and Dictionary&lt;String,Boolean&gt; 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
    }
}

pour ajouter de nouveaux types supportés à la classe, vous avez juste besoin d'ajouter votre classe, lui donner les bons constructeurs et les fonctions (regardez SurrogateDictionary pour un exemple), assurez-vous qu'il hérite de JsonSurrogateObject , et ajoutez son type de mapping au dictionnaire KnownTypes . Le substitut inclus peut servir de base pour n'importe quel type Dictionary<String,T> où T est n'importe quel type qui désérialise correctement.

L'appeler est vraiment simple:

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

notez que, pour une raison quelconque, cette chose a des difficultés à utiliser des chaînes de touches qui contiennent des espaces; ils n'étaient tout simplement pas présents dans la liste finale. Peut-être que c'est simplement contre les spécifications json et l'api que j'appelais étaient mal implémentées, Je ne sais pas. Quoi qu'il en soit, j'ai résolu cela par regex-en les remplaçant par des underscores dans les données brutes de json et en corrigeant le dictionnaire après la deserialisation.

2
répondu Nyerguds 2017-04-13 12:33:44

sur la Base des observations au-dessus essayer 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);

semble fonctionner même pour les objets complexes et les listes.

2
répondu FistOfFury 2017-12-19 22:55:54

je viens d'implémenter ceci dans RestSharp . Ce post a été utile pour moi.

Outre le code dans le lien, voici mon code. Je reçois maintenant un Dictionary de résultats quand je fais quelque chose comme ceci:

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>>();

soyez conscient du genre de JSON que vous attendez - dans mon cas, je récupérais un seul objet avec plusieurs propriétés. Dans le lien ci-joint, l'auteur cherchait une liste.

1
répondu northben 2013-05-02 18:59:37

mon approche désérialise directement à IDictionary, sans JObject ou ExpandObject entre les deux. Le code utilise le convertisseur, qui est essentiellement copié à partir de la classe de convertisseur D'ExpandoObject trouvée dans JSON.NET sourcecode, mais en utilisant Idicitionary au lieu de ExpandoObject.

Utilisation:

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

Code:

// 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;
    }
}
1
répondu Rafał Kłys 2014-05-26 10:21:24

assez fâcheusement, si vous voulez utiliser les reliures de modèle par défaut, il semble que vous devrez utiliser des valeurs d'index numériques comme un post de formulaire.

voir l'extrait suivant de cet article http://msdn.microsoft.com/en-us/magazine/hh781022.aspx :

bien que ce soit quelque peu contre-intuitif, les requêtes JSON ont les mêmes exigences-eux aussi doivent adhérer à la syntaxe de nommage du formulaire post. Prendre, par exemple, la charge utile JSON pour le prix unitaire précédent collection. La syntaxe pure du tableau JSON pour ces données serait représenté par:

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

cependant, les fournisseurs de valeurs par défaut et les reliures de modèle exigent les données pour être représenté comme un JSON post de formulaire:

{
  "UnitPrice[0].Code": "USD",
  "UnitPrice[0].Amount": 100.00,

  "UnitPrice[1].Code": "EUR",
  "UnitPrice[1].Amount": 73.64
}

le scénario complexe de collection d'objets est peut-être l'un des plus des scénarios largement problématiques que les développeurs rencontrent parce que le la syntaxe n'est pas forcément évident pour tous les développeurs. Cependant, une fois que vous apprendre la syntaxe relativement simple pour afficher des collections complexes, ces scénarios deviennent beaucoup plus faciles à traiter.

0
répondu jeremysawesome 2012-05-30 14:59:26

vous pouvez utiliser Tiny-JSON

string json = "{\"key1\":\"value1\", \"key2\":\"value2\"}";
IDictionary<string, string> dict = Tiny.Json.Decode<Dictionary<string, string>>(json);
0
répondu Robse 2016-09-21 11:23:32

un peu en retard au jeu, mais aucune des solutions ci-dessus m'a indiqué dans la direction d'un pur et simple. json.net solution. Alors voilà, ça a fini par être très simple. Ci-dessous un exemple complet de la façon dont il est fait avec la sérialisation standard .NET Json, l'exemple a un dictionnaire à la fois dans l'objet racine et dans les objets enfant.

la balle d'or est ce cat, analyse les paramètres comme deuxième paramètre de l'sérialiseur:

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

code complet ci-dessous:

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);
                        }
                    }
                }
            }
        }
    }
0
répondu Kjeld Poulsen 2017-12-13 15:45:00

je suggère d'utiliser System.Runtime.Serialization.Json qui fait partie de .NET 4.5.

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

alors utilisez - le comme ceci:

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);
0
répondu Dan Csharpster 2018-04-14 10:45:03