كيف يمكنني إلغاء تسلسل JSON إلى قاموس بسيط <string,string> في ASP.NET؟

StackOverflow https://stackoverflow.com/questions/1207731

سؤال

لدي قائمة مفاتيح/قيم بسيطة في JSON يتم إرسالها مرة أخرى إلى ASP.NET عبر POST.مثال:

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

أنا لا أحاول إلغاء التسلسل إلى كائنات .NET ذات نوع قوي

أنا ببساطة بحاجة إلى قديم عادي قاموس (من سلسلة، سلسلة), ، أو ما يعادله (جدول التجزئة، قاموس (من سلسلة، كائن)، المدرسة القديمة StringDictionary--الجحيم، مجموعة ثنائية الأبعاد من السلاسل ستعمل بالنسبة لي.

يمكنني استخدام أي شيء متوفر في ASP.NET 3.5، بالإضافة إلى Json.NET الشهير (الذي أستخدمه بالفعل للتسلسل) ل الزبون).

من الواضح أن أياً من مكتبات JSON هذه لا تمتلك هذه القدرة الواضحة المذهلة - فهي تركز بالكامل على إلغاء التسلسل القائم على الانعكاس عبر العقود القوية.

أيه أفكار؟

محددات:

  1. لا أريد تنفيذ محلل JSON الخاص بي
  2. لا يمكن استخدام ASP.NET 4.0 بعد
  3. أفضّل الابتعاد عن فئة ASP.NET الأقدم والمهملة لـ JSON
هل كانت مفيدة؟

المحلول

يقوم Json.NET بهذا ...

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

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

مزيد من الأمثلة: تسلسل المجموعات باستخدام Json.NET

نصائح أخرى

لقد اكتشفت أن .NET لديه طريقة مدمجة لإرسال سلسلة JSON إلى ملف Dictionary<String, Object> عبر System.Web.Script.Serialization.JavaScriptSerializer اكتب في 3.5 System.Web.Extensions حَشد.استخدم الطريقة DeserializeObject(String).

لقد عثرت على هذا عند إجراء منشور ajax (عبر jquery) لنوع المحتوى "application/json" إلى طريقة صفحة .net ثابتة ورأيت أن الطريقة (التي تحتوي على معلمة واحدة من النوع 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);

لقد واجهت نفس المشكلة، لذلك كتبت هذا بنفسي.يختلف هذا الحل عن الإجابات الأخرى لأنه يمكن إلغاء التسلسل إلى مستويات متعددة.

فقط أرسل سلسلة 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);
}

ملحوظة:مسقط رأس مزيد من نزع السلاح إلى أ Dictionary<string, object>هدف.

تحديث

تعمل إجابتي القديمة بشكل رائع إذا لم يكن هناك مصفوفة في سلسلة JSON.يتم إلغاء تسلسل هذا أيضًا إلى a List<object> إذا كان العنصر عبارة عن مصفوفة.

ما عليك سوى إرسال سلسلة JSON إلى إلغاء التسلسل إلى القاموس OrList الدالة سترجع غير مكتوبة بقوة 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))));
}

[أدرك أن هذا ينتهك قيود البروتوكول الاختياري رقم 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;
}

لقد أضفت فحصًا للقيم الخالية في JSON إلى الإجابة الأخرى

كان لدي نفس المشكلة لذلك كتبت هذا بنفسي.يتم تمييز هذا الحل عن الإجابات الأخرى لأنه يمكن أن يفرز في مستويات متعددة.

فقط أرسل سلسلة 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> هدف.

نشر مارك ريندل هذا كتعليق, ، أردت نشره كإجابة لأنه الحل الوحيد الذي نجح حتى الآن في إعادة النجاح ونتائج رموز الخطأ json من استجابة Google reCaptcha.

string jsonReponseString= wClient.DownloadString(requestUrl);    
IDictionary<string, object> dict = new JavaScriptSerializer().DeserializeObject(jsonReponseString) as IDictionary<string, object>;

شكرا مرة أخرى، مارك!

بناء على التعليقات فوق يحاول 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);

يبدو أنه يعمل حتى بالنسبة للكائنات والقوائم المعقدة.

يبدو أن كل هذه الإجابات هنا تفترض فقط أنه يمكنك إخراج تلك السلسلة الصغيرة من كائن أكبر ...للأشخاص الذين يتطلعون ببساطة إلى إلغاء تحديد كائن كبير باستخدام مثل هذا القاموس في مكان ما داخل التعيين، والذين يستخدمون 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&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 وأن واجهة برمجة التطبيقات التي كنت أتصل بها كانت سيئة التنفيذ، انتبه؛لا أدري.على أي حال، لقد قمت بحل هذه المشكلة عن طريق استبدالها بالتعبير العادي بشرطات سفلية في بيانات json الأولية وإصلاح القاموس بعد إلغاء التسلسل.

لقد قمت للتو بتنفيذ هذا في ريستشارب. هذا المشنور كان مفيدا بالنسبة لي.

بجانب الكود الموجود في الرابط، هذا هو الكود الخاص بي.أحصل الآن على 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;
    }
}

لقد تأخرت اللعبة بعض الشيء، ولكن لم يوجهني أي من الحلول المذكورة أعلاه نحو حل .NET نقي وبسيط، ولا يوجد حل json.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 السابقة.

[ 
  { "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
}

The complex object collection scenario is perhaps one of the most widely problematic scenarios that developers run into because the syntax isn’t necessarily evident to all developers. However, once you learn the relatively simple syntax for posting complex collections, these scenarios become much easier to deal with.

يمكنك استخدام صغير-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);
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top