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

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

我没有试图反序列化为强类型的.NET对象

我只需要一个普通的旧字典(Of String,String),或者一些等价的东西(哈希表,字典(OfString,Object),老式的StringDictionary——见鬼,一个二维字符串数组对我来说很有用。

我可以使用ASP.NET 3.5中可用的任何东西,也可以使用流行的Json.NET(我已经在使用它对客户端进行序列化)。

显然,这两个JSON库都没有这种开箱即用的能力——它们完全专注于通过强契约实现基于反射的反序列化。

有什么想法吗?

限制:

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


当前回答

根据上面的评论,尝试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);

似乎甚至适用于复杂的对象和列表。

其他回答

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

我在对静态.net页面方法进行内容类型为“application/json”的ajax发布(通过jquery)时偶然发现了这一点,并看到该方法(只有一个Object类型的参数)神奇地收到了这个字典。

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

gis.stackeexchange.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数据中用下划线替换它们,并在反序列化后修复字典来解决这个问题。

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

这是我使用System.Text.Json的解决方案。您可以获得嵌套对象的Json字符串,然后可以将其转换为所需类型。

public static Dictionary<string,string> JsonToDictionary(this string json)
        {
            var objectValues = JsonSerializer.Deserialize<Dictionary<string, object>>(json);
            var stringValues = objectValues.Select(o => new KeyValuePair<string, string>(o.Key, o.Value?.ToString()));
            return stringValues.ToDictionary(pair => pair.Key, pair => pair.Value);
        }

以下是从嵌套对象获取值的用法示例:

 var result= json.JsonToDictionary()["outerField"]
                .JsonToDictionary()["innerField"];

请注意,此解决方案不包括以数组形式开始的json对象,如[12,13]。这些对象可以在开头作为数组读取,然后可以在每个项上应用扩展方法,以防这些项是具有自己财产的复杂对象。

Json.NET执行此操作。。。

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

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

更多示例:使用Json.NET序列化集合