首页 文章

如何在ASP.NET中将JSON反序列化为简单的Dictionary <string,string>?

提问于
浏览
579

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

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

I AM NOT TRYING TO DESERIALIZE INTO STRONGLY-TYPED .NET OBJECTS

我只需要一个普通的旧的 Dictionary(Of String, String) ,或者一些等价的(哈希表,字典(Of String,Object),旧式的StringDictionary - 地狱,一个二维的字符串数组对我有用 .

我可以使用ASP.NET 3.5中的任何可用内容,以及流行的Json.NET(我已经用于序列化 to 客户端) .

显然,这些JSON库都没有开箱即用的前瞻性功能 - 它们完全专注于通过强大 Contract 进行基于反射的反序列化 .

有任何想法吗?

限制:

  • 我不想实现自己的JSON解析器

  • 尚未使用ASP.NET 4.0

  • 宁愿远离旧的,已弃用的JSON ASP.NET类

19 回答

  • 2

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

    当我将一个内容类型为'application/json'的ajax帖子(通过jquery)发送到一个静态.net页面方法时,我偶然发现了这一点,并看到该方法(具有 Object 类型的单个参数)神奇地接收了这个词典 .

  • 52

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

    [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);
    
  • 1

    似乎所有这些答案都假设你可以从一个更大的对象中得到那个小字符串...对于那些希望简单地在映射中的某个地方用这样的字典去实现一个大对象的人,以及谁正在使用 System.Runtime.Serialization.Json DataContract系统,这是一个解决方案:

    An answer on gis.stackexchange.comthis interesting link . 我必须使用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数据中的下划线替换它们并在反序列化后修复字典 .

  • 1

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

    我有同样的问题,所以我写了这个我自己 . 此解决方案与其他答案不同,因为它可以反序列化为多个级别 .

    只需将json字符串发送到 deserializeToDictionary 函数,它将返回非强类型的 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;
    }
    

    例如:这将返回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);
    }
    

    注意:hometown进一步反序列化为 Dictionary<string, object> 对象 .

  • 15

    游戏有点晚了,但没有上述解决方案使我指向纯粹简单的.NET,没有json.net解决方案 . 所以在这里,结果非常简单 . 下面是一个完整的运行示例,说明如何使用标准.NET Json序列化,该示例在根对象和子对象中都有字典 .

    黄金子弹是这只猫,将设置解析为序列化器的第二个参数:

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

    试图不使用任何外部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);
    
  • 4

    我刚刚在RestSharp中实现了这一点 . This post对我有帮助 .

    除了链接中的代码,这是我的代码 . 当我做这样的事情时,我现在得到 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 - 在我的例子中,我正在检索具有多个属性的单个对象 . 在附加链接中,作者正在检索列表 .

  • 0

    Mark Rendle发布了这个as a comment,我想发布它作为答案,因为它是目前为止唯一能够返回成功的解决方案,以及来自Google reCaptcha响应的错误代码json结果 .

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

    马克,再次感谢!

  • 10

    我的方法直接反序列化为IDictionary,中间没有JObject或ExpandObject . 代码使用转换器,它基本上是从JSON.NET源代码中的ExpandoObjectConverter类复制的,但是使用IDictionary而不是ExpandoObject .

    Usage:

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

    我添加了代码来创建 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;
    }
    
  • 94

    对于那些搜索互联网并绊倒这篇文章的人,我写了一篇关于如何使用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"]);
    
  • 3

    Json.NET这样做......

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

    更多例子:Serializing Collections with Json.NET

  • 5

    根据评论above试试 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);
    

    似乎甚至可以用于复杂的对象和列表 .

  • 0

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

    {
        "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对象 .

  • 2

    令人讨厌的是,如果你想使用默认的模型 Binders ,看起来你必须使用数字索引值,如表单POST .

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

    虽然它有点违反直觉,但JSON请求具有相同的要求 - 它们也必须遵循表单后命名语法 . 例如,获取前一个UnitPrice集合的JSON有效负载 . 此数据的纯JSON数组语法将表示为:[
    {“代码”:“美元”,“金额”:100.00},
    {“代码”:“欧元”,“金额”:73.64}
    ]
    但是,默认值提供程序和模型绑定程序要求将数据表示为JSON表单post:{
    “UnitPrice [0] .Code”:“USD”,
    “UnitPrice [0] .Amount”:100.00,

    “UnitPrice [1] .Code”:“EUR”,
    “UnitPrice [1] .Amount”:73.64
    }
    复杂的对象集合场景可能是开发人员遇到的最广泛问题的场景之一,因为语法并不一定对所有开发人员都很明显 . 但是,一旦您了解了发布复杂集合的相对简单的语法,这些场景就变得更容易处理 .

  • 0

    Edit: 这有效,但使用Json.NET接受的答案要简单得多 . 留下这个以防万一有人需要BCL专用代码 .

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

    <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的混合......

  • 3

    我有同样的问题,所以我写了这个我自己 . 此解决方案与其他答案不同,因为它可以反序列化为多个级别 .

    只需将JSON字符串发送到 deserializeToDictionary 函数,它将返回非强类型的 Dictionary<string, object> 对象 .

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

    例如:这将返回Facebook JSON响应的 Dictionary<string, object> 对象 .

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

    注意:hometown进一步deserilize为Dictionary <string,object>对象 .

    Update

    如果JSON字符串上没有数组,那么我的旧答案很有效 . 如果元素是数组,则进一步反序列化为 List<object> .

    只需将一个JSON字符串发送到 deserializeToDictionaryOrList 函数,它将返回非强类型的 Dictionary<string, 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;
        }
    }
    
  • 31

    如果您正在使用轻量级,无添加引用的方法,那么我刚写的这些代码可能会起作用(尽管我不能100%保证稳健性) .

    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,但从技术上讲,你没有写它,我做了]

  • 40

    你可以用Tiny-JSON

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

相关问题