我怎样才能反序列化JSON到一个简单的字典<string,string>在ASP.NET中?
我有一个简单的键/值列表JSON通过POST发送回ASP.NET。 例:
{ "key1": "value1", "key2": "value2"}
我不想尝试将.NET对象强制转换为强types
我只需要一个简单的老字典(string,string) ,或者一些等价的(哈希表,字典(string,对象),旧式的StringDictionary – 地狱,string的二维数组将适合我。
我可以使用ASP.NET 3.5中可用的任何东西,以及stream行的Json.NET(我已经用于序列化到客户端)。
显然,这些JSON库都没有这个额外的开箱即用的function – 它们完全专注于通过强大的合同进行基于reflection的反序列化。
有任何想法吗?
限制:
- 我不想实现我自己的JSONparsing器
- 目前还不能使用ASP.NET 4.0
- 宁愿远离旧的,不推荐使用JSON的ASP.NET类
Json.NET这样做…
string json = @"{""key1"":""value1"",""key2"":""value2""}"; var values = JsonConvert.DeserializeObject<Dictionary<string, string>>(json);
更多示例: 使用Json.NET序列化集合
我发现.NET有一个内置的方法Dictionary<String, Object>
通过3.5 System.Web.Extensions
程序集中的System.Web.Script.Serialization.JavaScriptSerializer
types将JSONstring转换为Dictionary<String, Object>
。 使用方法DeserializeObject(String)
。
我偶然发现了一个内容types为“application / json”的ajax post(通过jquery)到一个静态的.net Page Method,并看到这个方法(它有一个Object
types的单个参数)奇迹般的接收了这个Dictionary。
对于那些search互联网和绊倒这个职位,我写了一篇关于如何使用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"]);
试图不使用任何外部的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);
我有同样的问题,所以我写这个我的自我。 这个解决scheme与其他解答不同,因为它可以反序列化到多个级别。
只要将jsonstring发送到deserializeToDictionary函数,它将返回非强types的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.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); }
注意:家乡进一步deserilize成
Dictionary<string, object>
对象。
如果你是在一个轻量级的,没有添加引用types的方法之后,也许这个我刚刚写的代码将工作(虽然我不能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,但从技术上说,你没有写,我做了]
编辑:这工作,但接受的答案使用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的混合…
我只需要parsing一个嵌套的字典,就像
{ "x": { "a": 1, "b": 2, "c": 3 } }
JsonConvert.DeserializeObject
不起作用。 我发现了以下方法:
var dict = JObject.Parse(json).SelectToken("x").ToObject<Dictionary<string, int>>();
SelectToken
让你挖掘到所需的领域。 你甚至可以指定一个像"xyz"
这样的path进一步向下进入JSON对象。
我在JSON中添加了一个空值检查到另一个答案
我有同样的问题,所以我写这个我的自我。 这个解决scheme与其他解答不同,因为它可以反序列化到多个级别。
只要将jsonstring发送到deserializeToDictionary函数,它将返回非强types的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>
对象。
我在这里添加了jSnake04和Dasun提交的代码。 我已经添加了代码来从JArray
实例创build对象列表。 它有双向recursion,但由于它在一个固定的有限树模型上运行,除非数据量很大,否则不会有堆栈溢出的风险。
/// <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; }
Mark Rendle发表了这个评论,我想把它作为一个答案发布,因为它是唯一的解决scheme,迄今为止已经成功返回的成功和错误代码JSON结果从谷歌reCaptcha响应。
string jsonReponseString= wClient.DownloadString(requestUrl); IDictionary<string, object> dict = new JavaScriptSerializer().DeserializeObject(jsonReponseString) as IDictionary<string, object>;
再次感谢Mark!
看起来,所有这些答案都假设你可以从一个更大的对象中得到那个小string…对于那些希望简单地用映射内的某个字典去除大对象的人,以及使用System.Runtime.Serialization.Json
DataContract系统,这里有一个解决scheme:
gis.stackexchange.com上的答案有这个有趣的链接 。 我不得不使用archive.org来恢复它,但它提供了一个非常完美的解决scheme:一个自定义的IDataContractSurrogate
类,您可以在其中实现自己的types。 我能够轻松地扩展它。
不过,我做了一些改变。 由于原始来源不再可用,我将在这里发布整个课程:
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<String,String> and Dictionary<String,Boolean> 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 } }
要向类中添加新的受支持types,只需添加类,给它正确的构造函数和函数(例如查看SurrogateDictionary
),确保它inheritanceJsonSurrogateObject
,并将其types映射添加到KnownTypes
字典中。 包含的SurrogateDictionary可以作为任何Dictionary<String,T>
types的基础,其中T是任何正确反序列化的types。
调用它非常简单:
MyObjtype newObj = JsonSurrogate.Deserialize<MyObjtype>(jsonStr, encoding);
请注意,由于某些原因,使用包含空格的键string时, 他们根本不在最后的名单。 可能只是简单地反对json规范,我所说的api执行不力,请介意; 我不知道。 无论如何,我通过正则expression式来解决这个问题 – 用原始json数据中的下划线replace它们,并在反序列化之后修复字典。
我刚刚在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 – 就我而言,我正在检索一个具有多个属性的对象。 在附加的链接中,作者正在检索一个列表。
我的方法直接反序列化到IDictionary,没有之间的JObject或ExpandObject。 代码使用的转换器,基本上从JSON.NET源代码中的ExpandoObjectConverter类复制,但使用IDictionary而不是ExpandoObject。
用法:
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; } }
令人讨厌的是,如果你想使用默认的模型绑定器,看起来你将不得不使用数字索引值,如表单POST。
请参阅以下摘自本文的摘录http://msdn.microsoft.com/en-us/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 }
复杂的对象集合场景可能是开发人员遇到的最广泛的问题场景之一,因为语法对于所有开发人员来说都不一定是明显的。 但是,一旦学习了发布复杂集合的相对简单的语法,这些场景就变得更容易处理了。
我会build议使用.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);
If you don't want or can't add a large third-party library like Json.NET (for example, because you're using Unity3D), I really recommend taking a look at MiniJSON . Short and sweet code, easy to extend if there's something more you need.
You could use Tiny-JSON
string json = "{\"key1\":\"value1\", \"key2\":\"value2\"}"; IDictionary<string, string> dict = Tiny.Json.Decode<Dictionary<string, string>>(json);