asp.net-ajax - ASP.NET JSon如何反序列化为一个简单的Dictionary<string,string>?

  显示原文与译文双语对照的内容

我有一个简单的键/值列表,它通过POST返回到 ASP.NET 。 例如:


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

我并不是在反序列化成 STRONGLY-TYPED. NET 对象

我只需要一个普通的Dictionary(Of String, String),或者一些等价的( 哈希表,Dictionary(Of String, Object), old-school StringDictionary--hell,一个 2 -D数组,可以为我工作) 。

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

显然这两个JSON库都没有这个forehead-slapping明显的功能box--they完全集中在通过强契约的reflection-based反序列化。

有什么想法吗?

限制:

  1. 我不想实现我自己的JSON解析器
  2. 无法使用 ASP.NET 4.0
  3. 宁愿远离旧的过时的ASP.NET 类
时间:

Json.NET 执行这里操作。。


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

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

更多示例:序列化带有 Json.NET的集合

我发现. NET 有一个内置的方法,可以通过 System.Web.Script.Serialization.JavaScriptSerializer 输入 3.5 System.Web.Extensions 程序集。 使用方法 DeserializeObject(String)

我偶然发现了这个在ajax post ( 通过 jquery ) 内容类型'应用程序/json'静态. NET 页面方法,发现方法( 它有一个类型为 Object的参数) 神奇地收到了这本字典。

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

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

只是发送json字符串 deserializeToDictionary 函数会返回非 strongly-typed 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> 对象。

如果你在一个轻量级,no-added-references方法,也许这我刚写的代码将( 不能 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))));
}

[I realise that this violates the OP Limitation yf_str_emysy888_yf_str but technically, you didn't write it, i did ]

的编辑: 可以工作,但使用 Json.NET 所接受的答案要简单得多。 如果有人需要BCL-only代码,就离开这个。

.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. 混合使用。

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

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

只是发送json字符串 deserializeToDictionary 函数会返回非 strongly-typed 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);
}

注意:家乡进一步反序列化为 Dictionary<string, object> 对象。

我刚在 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 。 代码使用转换器,这基本上是照搬ExpandoObjectConverter类 Json.NET 源代码里,但使用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;
 }
}

...