私はJSONでPOSTを介してASP.NETに返送される簡単なキー/値リストを持っています。例:
{ "key1": "value1", "key2": "value2"}
厳密にタイプされた.NETオブジェクトへの正規化を試みない
単に古い Dictionary(Of String、String) 、または同等のもの(ハッシュテーブル、Dictionary(Of String、Object)、old-school StringDictionary - 地獄、文字列の2-D配列がうまくいくでしょう)私のために。
私はASP.NET 3.5で利用可能なものなら何でも使用することができます(そして私はすでにシリアライゼーション to クライアントに使用しています)。
どうやらこれらのJSONライブラリのどちらも箱から出してすぐにこの額をたたく明白な能力を持っていません - 彼らは強い契約による反射ベースの逆シリアル化に完全に焦点を合わせています。
何か案は?
制限事項
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 Page Methodにコンテンツタイプ 'application/json'の(jqueryによる)ajax投稿をするとき、私はこれにつまずいて、(タイプObject
の単一パラメータを持つ)メソッドが魔法のようにこのDictionaryを受け取ることを見ました。
インターネットを検索してこの記事に悩まされている人のために、私は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);
私は同じ問題を抱えていたので、私はこれを私の自己と書いた。このソリューションは、複数のレベルにデシリアライズできるため、他の答えとは区別されます。
JSON文字列を deserializeToDictionary 関数に送信するだけで、厳密には型指定されていないDictionary<string, object>
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);
}
注意:出身地はさらに
Dictionary<string, object>
オブジェクトになります。
アップデート
私の昔の答えはJSON文字列に配列がない場合にはうまくいきます。要素が配列の場合、これはさらにList<object>
にデシリアライズします。
JSON文字列を deserializeToDictionaryOrList functionに送信するだけで、厳密には型指定されていないDictionary<string, object>
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;
}
}
軽量で、参照を追加しないようなアプローチを取っているのであれば、たぶん私が書いたこのコードはうまくいくでしょう。
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 Frameworkでは、そのままではサポートされていません。明白な監視 - すべての人が名前付きプロパティを持つオブジェクトに逆シリアル化する必要はありません。それで、私は自分自身を転がしました:
<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はこれを コメントとして として投稿しました。成功したこと、およびエラーコードjsonがGoogleのreCaptchaレスポンスの結果として返されるのはこれまでのところ唯一の解決策だからです。
string jsonReponseString= wClient.DownloadString(requestUrl);
IDictionary<string, object> dict = new JavaScriptSerializer().DeserializeObject(jsonReponseString) as IDictionary<string, object>;
ありがとう、マーク!
私は他の答えにJSONのnull値のチェックを追加しました
私は同じ問題を抱えていたので、私はこれを私の自己と書いた。このソリューションは、複数のレベルにデシリアライズできるため、他の答えとは区別されます。
Json文字列を deserializeToDictionary functionに送るだけで、強く型付けされていないDictionary<string, object>
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>
オブジェクトに逆シリアル化します。
ここでのこれらの答えはすべて、あなたが大きなオブジェクトから小さな文字列を取り出すことができると仮定しているようです...マッピング内のどこかにそのような辞書で大きなオブジェクトを非現実化したい人、および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データにアンダースコアを使用して正規表現に置き換え、逆シリアル化後に辞書を修正することでこれを解決しました。
コメントに基づく 上記 try 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);
複雑なオブジェクトやリストに対してもうまくいくようです。
私のアプローチは、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;
}
}
私はこれを 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の種類に注意してください - 私の場合、私はいくつかのプロパティを持つ単一のオブジェクトを取得していました。添付のリンクで、作者はリストを検索していました。
ゲームには少し遅れましたが、上記の解決策のどれもが純粋で単純な.NET、json.netの解決策ではないことを示していました。だからここでそれは、結局非常に単純であることになった。標準的な.NET Jsonシリアライゼーションを使用した実行方法の完全な実行例の下に、この例のルートオブジェクトと子オブジェクトの両方に辞書があります。
黄金の弾丸はこの猫です。シリアライザへの2番目のパラメータとして設定を解析します。
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/ja-jp/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 }
構文が必ずしもすべての開発者にとって明白であるとは限らないため、複雑なオブジェクト収集のシナリオは、おそらく開発者が遭遇する最も広く問題のあるシナリオの1つです。ただし、複雑なコレクションを投稿するための比較的単純な構文を習得すると、これらのシナリオの処理がはるかに簡単になります。
.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);
Tiny-JSON を使えます
string json = "{\"key1\":\"value1\", \"key2\":\"value2\"}";
IDictionary<string, string> dict = Tiny.Json.Decode<Dictionary<string, string>>(json);