如何将JSON反序列化为简单的字典< string,string>

How can I deserialize JSON to a simple Dictionary<string,string> in ASP.NET?

我在JSON中有一个简单的键/值列表,通过POST发送回ASP.NET。例子:

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

我不想反序列化为强类型的.NET对象

我只需要一个简单的旧字典(字符串,字符串),或者一些等价的(哈希表,字典(字符串,对象),旧的学校字符串字典——见鬼,一个二维字符串数组就可以了。

我可以使用ASP.NET 3.5中可用的任何内容,以及流行的JSON.NET(我已经使用它对客户端进行序列化)。

显然,这两个JSON库都没有这样的能力——它们完全专注于通过强契约进行基于反射的反序列化。

有什么想法吗?

限制:

  • 我不想实现我自己的JSON解析器
  • 尚不能使用ASP.NET 4.0
  • 希望远离旧的、不推荐使用的用于JSON的ASP.NET类

  • json.net是这样做的…

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

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

    更多示例:用json.net序列化集合


    我发现.NET有一种内置的方法,可以通过3.5 System.Web.Extensions程序集中的System.Web.Script.Serialization.JavaScriptSerializer类型将json字符串强制转换为Dictionary类型。使用方法DeserializeObject(String)

    我在对静态.NET页面方法执行内容类型'application/json'的ajax post(通过jquery)时偶然发现了这一点,并看到该方法(具有类型Object的单个参数)神奇地收到了这本字典。


    对于那些在互联网上搜索并在这篇文章上绊倒的人,我写了一篇关于如何使用JavaScriptSerializer类的博客文章。

    阅读更多…http://procbits.com/2011/04/21/quick-json-serialization反序列化-in-c/

    下面是一个例子:

    1
    2
    3
    4
    5
    var json ="{"id":"13", "value": true}";
    var jss = new JavaScriptSerializer();
    var table = jss.Deserialize<dynamic>(json);
    Console.WriteLine(table["id"]);
    Console.WriteLine(table["value"]);


    尝试不使用任何外部JSON实现,因此我反序列化如下:

    1
    2
    3
    4
    5
    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字符串发送到反序列化字典函数中,它将返回非强类型Dictionary对象。

    旧代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    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对象。

    试验

    1
    2
    3
    4
    5
    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 further deserilize into a Dictionary
    object.

    更新

    如果JSON字符串上没有数组,我以前的回答就很好了。如果一个元素是一个数组,那么这个元素将进一步反序列化到List中。

    只需发送一个JSON字符串来反序列化etodiactionarlylist函数,它将返回非强类型的Dictionary对象或List

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    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;
        }
    }


    如果您追求的是一种轻量级的、没有添加引用的方法,也许我刚刚编写的这段代码可以工作(但我不能100%保证健壮性)。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    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))));
    }

    [我知道这违反了操作限制1,但从技术上讲,你没有写,我写了]


    我只需要分析一个嵌套字典,比如

    1
    2
    3
    4
    5
    6
    7
    {
       "x": {
           "a": 1,
           "b": 2,
           "c": 3
        }
    }

    JsonConvert.DeserializeObject却无济于事。我发现了以下方法:

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

    SelectToken可以让您深入到所需的区域。您甚至可以指定一个类似于"x.y.z"的路径来进一步进入JSON对象。


    我在这里添加了jsnake04和dasun提交的代码。我添加了代码来创建来自JArray实例的对象列表。它有双向递归,但由于它在固定的有限树模型上运行,所以除非数据量很大,否则不会有堆栈溢出的风险。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    /// <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;
    }

    编辑:这是可行的,但是使用json.net接受的答案要简单得多。如果有人只需要BCL代码,就留下这个。

    它不受.NET框架的开箱即用支持。一个明显的疏忽——并不是每个人都需要反序列化为具有命名属性的对象。所以我最后自己滚了:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    <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

    呼叫方式:

    1
    2
    3
    4
    5
    6
    7
    8
    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的混合…


    我在另一个答案中添加了对JSON中空值的检查

    我也有同样的问题,所以我自己写了这个。这个解决方案是与其他答案不同,因为它可以反序列化到多层次。

    只需将JSON字符串发送到反序列化字典中将返回非强类型Dictionary对象。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    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的Dictionary对象JSON响应。

    1
    2
    3
    4
    5
    6
    7
    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);
    }

    注:hostway进一步反序列化为Dictionary对象。


    Mark Rendle将此作为评论发布,我想将其作为答案发布,因为这是迄今为止唯一有效的返回成功的解决方案,以及Google Recaptcha响应中的错误代码json结果。

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

    再次感谢,马克!


    根据以上评论,试试JsonConvert.DeserializeObject>(json)

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

    似乎对复杂的对象和列表也有效。


    似乎所有这些答案都是假设你能从一个更大的物体中得到一根小绳子…对于那些只想在地图中某个地方用这样一个字典来简单地破坏一个大对象的人,以及那些使用System.Runtime.Serialization.Json数据合同系统的人,这里有一个解决方案:

    在gis.stackexchange.com上的一个答案有这个有趣的链接。我不得不用archive.org来恢复它,但它提供了一个非常完美的解决方案:一个定制的IDataContractSurrogate类,在这个类中,您完全实现了自己的类型。我可以很容易地扩展它。

    不过,我做了很多改动。由于原始源不再可用,我将在此处发布整个类:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    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字典。所包含的代理字典可以作为任何Dictionary类型的基础,其中t是任何正确反序列化的类型。

    称之为"非常简单:

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

    请注意,由于某些原因,使用包含空格的键字符串时会遇到问题;它们只是不在最终列表中。可能仅仅是因为它违反了JSON规范,而且我调用的API没有很好地实现,请注意,我不知道。无论如何,我通过regex在原始JSON数据中用下划线替换它们并在反序列化后修复字典来解决这个问题。


    我刚在RestSharp中实现了这一点。这篇文章对我有帮助。

    除了链接中的代码,这是我的代码。当我这样做的时候,我现在得到了一个Dictionary的结果:

    1
    2
    3
    4
    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类型——在我的例子中,我检索的是一个具有多个属性的对象。在附加的链接中,作者正在检索列表。


    我的方法直接反序列化到IDictionary,中间没有Jobject或ExpandObject。代码使用converter,它基本上是从json.net源代码中的expandoobjectconverter类复制的,但使用的是idictionary而不是expandoobject。

    用途:

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

    代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    // 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;
        }
    }


    游戏进行得有点晚了,但上面的解决方案中没有一个能为我指明一个纯粹而简单的.NET解决方案的方向,而不是JSON.NET解决方案。就这样,结果很简单。下面是一个完整的运行示例,说明如何使用标准的.NET JSON序列化来完成它,该示例在根对象和子对象中都有字典。

    金色的子弹就是这只猫,将设置作为序列化程序的第二个参数进行解析:

    1
    2
    3
    DataContractJsonSerializerSettings settings =
                           new DataContractJsonSerializerSettings();
                        settings.UseSimpleDictionaryFormat = true;

    完整代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    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);
                            }
                        }
                    }
                }
            }
        }


    令人恼火的是,如果你想使用默认的模型绑定器,看起来你必须使用数字索引值,就像表单发布一样。

    请参阅本文的以下摘录http://msdn.microsoft.com/en-us/magazine/hh781022.aspx:

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

    1
    2
    3
    4
    [
      {"Code":"USD","Amount": 100.00 },
      {"Code":"EUR","Amount": 73.64 }
    ]

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

    1
    2
    3
    4
    5
    6
    7
    {
     "UnitPrice[0].Code":"USD",
     "UnitPrice[0].Amount": 100.00,

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

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


    你可以使用微型JSON

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


    我建议使用System.Runtime.Serialization.Json,这是.NET 4.5的一部分。

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

    然后这样使用:

    1
    2
    3
    4
    5
    6
    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);