web-dev-qa-db-ja.com

ASP.NETでJSONを単純なDictionary <文字列、文字列>に逆シリアル化する方法を教えてください。

私はJSONでPOSTを介してASP.NETに返送される簡単なキー/値リストを持っています。例:

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

厳密にタイプされた.NETオブジェクトへの正規化を試みない

単に古い Dictionary(Of String、String) 、または同等のもの(ハッシュテーブル、Dictionary(Of String、Object)、old-school StringDictionary - 地獄、文字列の2-D配列がうまくいくでしょう)私のために。

私はASP.NET 3.5で利用可能なものなら何でも使用することができます(そして私はすでにシリアライゼーション to クライアントに使用しています)。

どうやらこれらのJSONライブラリのどちらも箱から出してすぐにこの額をたたく明白な能力を持っていません - 彼らは強い契約による反射ベースの逆シリアル化に完全に焦点を合わせています。

何か案は?

制限事項

  1. 自分のJSONパーサーを実装したくない
  2. ASP.NET 4.0はまだ使用できません
  3. JSON用の古い、非推奨のASP.NETクラスを避けたいと思うでしょう。
605
richardtallent

Json.NETはこれを行います...

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

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

その他の例: Json.NETによるコレクションの直列化

799

.NETには、3.5 Dictionary<String, Object>アセンブリのSystem.Web.Script.Serialization.JavaScriptSerializer型を介してJSON文字列をSystem.Web.Extensionsにキャストする方法が組み込まれていることがわかりました。メソッドDeserializeObject(String)を使用してください。

静的な.net Page Methodにコンテンツタイプ 'application/json'の(jqueryによる)ajax投稿をするとき、私はこれにつまずいて、(タイプObjectの単一パラメータを持つ)メソッドが魔法のようにこのDictionaryを受け取ることを見ました。

96
Crispy

インターネットを検索してこの記事に悩まされている人のために、私はJavaScriptSerializerクラスの使い方に関するブログ記事を書いた。

続きを読む... http://procbits.com/2011/04/21/quick-json-serializationdeserialization-in-c/

これが一例です。

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

外部のJSON実装を使用しないようにしたので、次のようにシリアル化解除しました。

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);
40
PvH

私は同じ問題を抱えていたので、私はこれを私の自己と書いた。このソリューションは、複数のレベルにデシリアライズできるため、他の答えとは区別されます。

JSON文字列を deserializeToDictionary 関数に送信するだけで、厳密には型指定されていないDictionary<string, object>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.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;
}

例:これはFacebook JSONレスポンスのDictionary<string, object>オブジェクトを返します。

テスト

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

注意:出身地はさらにDictionary<string, object>オブジェクトになります。

アップデート

私の昔の答えはJSON文字列に配列がない場合にはうまくいきます。要素が配列の場合、これはさらにList<object>にデシリアライズします。

JSON文字列を deserializeToDictionaryOrList functionに送信するだけで、厳密には型指定されていないDictionary<string, object>objectまたは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;
    }
}
34
Dasun

軽量で、参照を追加しないようなアプローチを取っているのであれば、たぶん私が書いたこのコードはうまくいくでしょう。

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

[私はこれがOP制限#1に違反していることを認識していますが、技術的には、あなたはそれを書かなかった、私はしました]

16
dexy

ネスト 辞書をパースするだけでいい

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

JsonConvert.DeserializeObjectは役に立ちません。私は以下のアプローチを見つけました:

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

SelectTokenを使用すると、目的のフィールドまで掘り下げることができます。 "x.y.z"のようなパスを指定してさらにJSONオブジェクトに進むこともできます。

13
Falko

編集: これは動作しますが、Json.NETを使用した一般的な回答はもっと簡単です。誰かがBCLのみのコードを必要とする場合に備えて、これを残してください。

.NET Frameworkでは、そのままではサポートされていません。明白な監視 - すべての人が名前付きプロパティを持つオブジェクトに逆シリアル化する必要はありません。それで、私は自分自身を転がしました:

<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

と呼ばれる:

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

C#とVB.NETの組み合わせでごめんね…

5
richardtallent

私はここにjSnake04とDasunによって提出されたコードを追加しました。 JArrayインスタンスからオブジェクトのリストを作成するためのコードを追加しました。双方向の再帰がありますが、固定の有限ツリーモデルで機能しているため、データが大量でない限り、スタックオーバーフローのリスクはありません。

/// <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;
}
5
Jordan

Mark Rendleはこれを コメントとして として投稿しました。成功したこと、およびエラーコードjsonがGoogleのreCaptchaレスポンスの結果として返されるのはこれまでのところ唯一の解決策だからです。

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

ありがとう、マーク!

4
Bryan

私は他の答えにJSONのnull値のチェックを追加しました

私は同じ問題を抱えていたので、私はこれを私の自己と書いた。このソリューションは、複数のレベルにデシリアライズできるため、他の答えとは区別されます。

Json文字列を deserializeToDictionary functionに送るだけで、強く型付けされていないDictionary<string, object>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;
}

例:これはFacebook JSONレスポンスのDictionary<string, object>オブジェクトを返します。

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

注意:出身地はさらにDictionary<string, object>オブジェクトに逆シリアル化します。

4
jSnake04

ここでのこれらの答えはすべて、あなたが大きなオブジェクトから小さな文字列を取り出すことができると仮定しているようです...マッピング内のどこかにそのような辞書で大きなオブジェクトを非現実化したい人、およびSystem.Runtime.Serialization.Json DataContractシステムを使用している人のために、ここに解決策があります:

gis.stackexchange.comの回答 がありました この興味深いリンク 。 archive.orgでそれを回復しなければなりませんでしたが、それは非常に完璧な解決策を提供します:独自の型を正確に実装するカスタムIDataContractSurrogateクラスです。簡単に拡張できました。

しかし、私はそれに多くの変更を加えました。元のソースは利用できないため、クラス全体をここに投稿します。

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

新しいサポートされている型をクラスに追加するには、クラスを追加し、適切なコンストラクターと関数を与えて(例としてSurrogateDictionaryを見て)、JsonSurrogateObjectを継承することを確認し、 KnownTypes辞書へのタイプマッピング。付属のSurrogateDictionaryは、Dictionary<String,T>型のベースとして機能します。Tは、正しく逆シリアル化される型です。

それを呼び出すことは本当に簡単です:

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

何らかの理由で、スペースを含むキー文字列の使用には問題があることに注意してください。それらは単に最終リストに含まれていませんでした。単にjsonの仕様に反しているだけかもしれませんが、私が呼び出していたapiは実装が不十分でした。私は知らないよ。とにかく、生のJSONデータにアンダースコアを使用して正規表現に置き換え、逆シリアル化後に辞書を修正することでこれを解決しました。

3
Nyerguds

コメントに基づく 上記 try 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);

複雑なオブジェクトやリストに対してもうまくいくようです。

2
FistOfFury

私のアプローチは、JObjectやExpandObjectを介さずに直接IDictionaryに逆シリアル化します。このコードは、基本的にJSON.NETソースコードにあるExpandoObjectConverterクラスからコピーされたコンバーターを使用しますが、ExpandoObjectの代わりにIDictionaryを使用します。

使用法:

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

コード:

// 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
Rafał Kłys

私はこれを RestSharp に実装したところです。 この記事 は私にとって役に立ちました。

リンク内のコード以外に、これが私のコードです。私は今、私がこのようなことをするとき、結果のDictionaryを得ます:

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

あなたが期待しているJSONの種類に注意してください - 私の場合、私はいくつかのプロパティを持つ単一のオブジェクトを取得していました。添付のリンクで、作者はリストを検索していました。

1
northben

ゲームには少し遅れましたが、上記の解決策のどれもが純粋で単純な.NET、json.netの解決策ではないことを示していました。だからここでそれは、結局非常に単純であることになった。標準的な.NET Jsonシリアライゼーションを使用した実行方法の完全な実行例の下に、この例のルートオブジェクトと子オブジェクトの両方に辞書があります。

黄金の弾丸はこの猫です。シリアライザへの2番目のパラメータとして設定を解析します。

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

以下の完全なコード:

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
Kjeld Poulsen

厄介なことに、デフォルトのモデルバインダーを使用したい場合は、フォームのPOSTのように数値のインデックス値を使用する必要があるように見えます。

この記事からの抜粋を参照してください http://msdn.Microsoft.com/ja-jp/magazine/hh781022.aspx

やや直観的ではありませんが、JSONリクエストにも同じ要件があります。それらもフォームポストネーミング構文に従う必要があります。たとえば、前のUnitPriceコレクションのJSONペイロードを取ります。このデータの純粋なJSON配列構文は次のように表されます。

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

ただし、デフォルト値プロバイダーおよびモデルバインダーでは、データをJSONフォームの投稿として表す必要があります。

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

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

構文が必ずしもすべての開発者にとって明白であるとは限らないため、複雑なオブジェクト収集のシナリオは、おそらく開発者が遭遇する最も広く問題のあるシナリオの1つです。ただし、複雑なコレクションを投稿するための比較的単純な構文を習得すると、これらのシナリオの処理がはるかに簡単になります。

0
jeremysawesome

.NET 4.5の一部であるSystem.Runtime.Serialization.Jsonを使用することをお勧めします。

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

それからこのようにそれを使ってください:

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
Dan Csharpster

Tiny-JSON を使えます

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