JSON을 간단한 사전으로 역 직렬화하는 방법 ASP.NET에서?
JSON으로 된 간단한 키 / 값 목록이 POST를 통해 ASP.NET으로 다시 전송됩니다. 예:
{ "key1": "value1", "key2": "value2"}
강력한 형식의 .NET 개체를 탐색하지 않습니다.
나는 단순히 평범한 오래된 Dictionary (Of String, String) 또는 동등한 것 (hash table, Dictionary (Of String, Object), 구식 StringDictionary-hell, 2D 문자열 배열이 나를 위해 작동합니다.
ASP.NET 3.5에서 사용 가능한 모든 것을 사용할 수 있으며 인기있는 Json.NET (이미 클라이언트에 대한 직렬화 에 사용 하고 있음)을 사용할 수 있습니다.
분명히 이러한 JSON 라이브러리 중 어느 것도 이마저도 튀는 명백한 기능을 가지고 있지 않습니다. 강력한 계약을 통한 반사 기반 역 직렬화에 전적으로 초점을 맞추고 있습니다.
어떤 아이디어?
제한 사항 :
- 내 자신의 JSON 파서를 구현하고 싶지 않습니다.
- 아직 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에는 3.5 어셈블리 Dictionary<String, Object>
의 System.Web.Script.Serialization.JavaScriptSerializer
유형을 통해 JSON 문자열을 캐스트하는 방법이 내장되어 있음을 발견했습니다 System.Web.Extensions
. 방법을 사용하십시오 DeserializeObject(String)
.
정적 .net 페이지 메서드에 콘텐츠 유형 'application / json'의 ajax 게시물 (jquery를 통해)을 수행 할 때 이것을 우연히 발견했고 메서드 (유형의 단일 매개 변수가있는 Object
)가이 사전을 마술처럼 수신 했음을 알았습니다 .
인터넷을 검색하고이 게시물에 걸려 넘어지는 사람들을 위해 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);
나도 같은 문제가있어서 이것을 직접 썼다. 이 솔루션은 여러 수준으로 역 직렬화 할 수 있기 때문에 다른 답변과 다릅니다.
deserializeToDictionary 함수 에 JSON 문자열을 보내면 강력한 형식이 아닌 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;
}
예 : Dictionary<string, object>
Facebook JSON 응답의 개체를 반환 합니다.
테스트
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>
.
최신 정보
JSON 문자열에 배열이 없으면 내 이전 답변이 훌륭하게 작동합니다. 이것은 List<object>
요소가 배열 인 경우 추가로 deserialize 합니다.
deserializeToDictionaryOrList 함수 에 JSON 문자열을 보내면 강력한 형식이 아닌 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;
}
}
가볍고 참조가 추가되지 않은 접근 방식을 원한다면 방금 작성한 코드가 작동 할 것입니다 (하지만 견고성을 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을 위반한다는 것을 알고 있지만 기술적으로는 작성하지 않았습니다.
중첩 된 사전 을 구문 분석해야합니다.
{
"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 객체로 더 내려가는 것과 같은 경로를 지정할 수도 있습니다 .
편집 : 이것은 작동하지만 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을 섞어서 죄송합니다…
여기에 jSnake04와 Dasun이 제출 한 코드에 추가했습니다. 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;
}
Mark Rendle은 이것을 주석 으로 게시했습니다. 지금까지 성공을 반환하고 Google reCaptcha 응답의 오류 코드 json 결과를 반환하는 유일한 솔루션이기 때문에 답변으로 게시하고 싶었습니다.
string jsonReponseString= wClient.DownloadString(requestUrl);
IDictionary<string, object> dict = new JavaScriptSerializer().DeserializeObject(jsonReponseString) as IDictionary<string, object>;
다시 한 번 감사드립니다, 마크!
다른 답변에 JSON의 null 값 확인을 추가했습니다.
나는 같은 문제가있어서 이것을 내 자신으로 썼다. 이 솔루션은 여러 수준으로 역 직렬화 할 수 있기 때문에 다른 답변과 다릅니다.
deserializeToDictionary 함수 에 json 문자열을 보내면 강력한 형식이 아닌 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;
}
예 : Dictionary<string, object>
Facebook JSON 응답의 개체를 반환 합니다.
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>
객체 로 더 역 직렬화됩니다 .
여기에있는 모든 답변은 더 큰 객체에서 작은 문자열을 얻을 수 있다고 가정합니다 ... 매핑 내부 어딘가에 그러한 사전이있는 큰 객체를 단순히 비 현실화하려는 사람들과 System.Runtime.Serialization.Json
DataContract 시스템을 사용하는 사람들을 위해 다음 과 같습니다. 해결책 :
gis.stackexchange.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<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
}
}
새로운 지원 유형을 클래스에 추가하려면 클래스를 추가하고 올바른 생성자와 함수를 SurrogateDictionary
제공하고 (예제 참조)을 상속하는지 확인 JsonSurrogateObject
하고 KnownTypes
사전에 유형 매핑을 추가하기 만하면 됩니다. 포함 된 SurrogateDictionary는 Dictionary<String,T>
T가 올바르게 역 직렬화되는 모든 유형 인 모든 유형의 기반으로 사용할 수 있습니다.
호출하는 것은 정말 간단합니다.
MyObjtype newObj = JsonSurrogate.Deserialize<MyObjtype>(jsonStr, encoding);
어떤 이유로이 것은 공백을 포함하는 키 문자열을 사용하는 데 문제가 있습니다. 그들은 단순히 최종 목록에 없었습니다. 단순히 json 사양에 반하는 것일 수 있으며 내가 호출 한 API가 제대로 구현되지 않았을 수도 있습니다. 몰라요. 어쨌든, 원시 json 데이터에서 밑줄로 정규식 대체하고 역 직렬화 후 사전을 수정하여이 문제를 해결했습니다.
위의 의견을 바탕으로 시도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);
복잡한 개체와 목록에서도 작동하는 것 같습니다.
방금 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의 종류를 염두에 두십시오. 제 경우에는 여러 속성이있는 단일 객체를 검색했습니다. 첨부 된 링크에서 저자는 목록을 검색하고있었습니다.
내 접근 방식은 JObject 또는 ExpandObject없이 IDictionary로 직접 역 직렬화합니다. 이 코드는 기본적으로 JSON.NET 소스 코드에있는 ExpandoObjectConverter 클래스에서 복사 된 변환기를 사용하지만 ExpandoObject 대신 IDictionary를 사용합니다.
용법:
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;
}
}
게임에 조금 늦었지만 위의 솔루션 중 어느 것도 json.net 솔루션이 아닌 순수하고 단순한 .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);
}
}
}
}
}
}
성가 시게도 기본 모델 바인더를 사용하려면 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 }
복잡한 개체 수집 시나리오는 구문이 모든 개발자에게 반드시 분명한 것은 아니기 때문에 개발자가 실행하는 가장 광범위한 문제 시나리오 중 하나 일 것입니다. 그러나 복잡한 컬렉션을 게시하는 비교적 간단한 구문을 배우면 이러한 시나리오를 훨씬 쉽게 처리 할 수 있습니다.
Tiny-JSON을 사용할 수 있습니다.
string json = "{\"key1\":\"value1\", \"key2\":\"value2\"}";
IDictionary<string, string> dict = Tiny.Json.Decode<Dictionary<string, string>>(json);
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);
'code' 카테고리의 다른 글
Eclipse, Subclipse 및 Subversive 용 SVN 플러그인의 장단점은 무엇입니까? (0) | 2020.10.02 |
---|---|
위조, 조롱 및 스터 빙의 차이점은 무엇입니까? (0) | 2020.10.02 |
모든 jQuery Ajax 요청이 완료 될 때까지 기다리시겠습니까? (0) | 2020.10.02 |
임베디드 리소스 텍스트 파일 읽는 방법 (0) | 2020.10.02 |
ASP.NET MVC-사용자 지정 IIdentity 또는 IPrincipal 설정 (0) | 2020.10.02 |