ฉันจะ deserialize JSON ให้กับ Dictionary <string, string> อย่างง่ายใน ASP.NET ได้อย่างไร?


682

ฉันมีรายการคีย์ / ค่าอย่างง่ายใน JSON ที่ถูกส่งกลับไปยัง ASP.NET ผ่าน POST ตัวอย่าง:

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

ฉันไม่ได้พยายามที่จะกำหนดค่าให้เป็น. NET Objected

ฉันเพียงต้องการพจนานุกรมแบบเก่าธรรมดา(ของสตริง, สตริง)หรือเทียบเท่า (ตารางแฮช, พจนานุกรม (ของสตริง, วัตถุ), StringDictionary โรงเรียนเก่า - นรกอาร์เรย์ 2 มิติของสตริงจะใช้งานได้สำหรับฉัน

ฉันสามารถใช้สิ่งใดก็ได้ที่มีใน ASP.NET 3.5 เช่นเดียวกับ Json.NET ที่เป็นที่นิยม (ซึ่งฉันใช้อยู่แล้วสำหรับการทำให้เป็นอนุกรมกับไคลเอ็นต์)

เห็นได้ชัดว่าไม่มีไลบรารี JSON เหล่านี้ที่มีความสามารถในการตบหน้าผากอย่างเห็นได้ชัด - พวกเขามุ่งเน้นไปที่การกำจัดซีเรียลไลเซชั่นแบบสะท้อนผ่านสัญญาที่แข็งแกร่ง

ความคิดใด ๆ

ข้อ จำกัด :

  1. ฉันไม่ต้องการใช้เครื่องมือแยกวิเคราะห์ JSON ของตัวเอง
  2. ยังไม่สามารถใช้ ASP.NET 4.0
  3. ต้องการหลีกเลี่ยงคลาส ASP.NET ที่เก่ากว่าและเลิกใช้แล้วสำหรับ JSON

1
Re: ข้อ จำกัด 3 JavaScriptSerizlizerใช้ใน ASP.NET MVC และไม่เลิกใช้แล้ว
bdukes

17
มันเหลือเชื่อว่ามันยากที่จะหาวิธีง่ายๆในการแปลงสตริง json เป็นสิ่งที่ฉันสามารถใช้งานได้ง่ายโดยไม่ต้องพลิกผ่าน stackoverflow ที่แตกต่างกันมากมาย มันง่ายมากในภาษาอื่น ๆ แต่ Java และ C # ดูเหมือนจะออกนอกเส้นทางเพื่อทำให้ชีวิตลำบาก
user299709

คำตอบ:


893

Json.NETทำสิ่งนี้ ...

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

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

ตัวอย่างเพิ่มเติม: การทำให้เป็นอันดับคอลเลกชันกับ Json.NET


9
สิ่งนี้ยังใช้งานได้เมื่อค่าของคุณเป็นจำนวนเต็ม พวกเขาถูกโยนโดยอัตโนมัติเพื่อ 'สตริง'?
Highmastdon

58
@ Highmastdon ไม่มีไม่ได้ ฉันได้พบวิธีที่ดีที่สุดในการดีdynamicJsonConvert.DeserializeObject<Dictionary<string, dynamic>>(json);
ซีเรียลไลซ์

1
ลองคำตอบหลายข้อในหน้านี้ด้วยคู่คีย์ / ค่าที่ยุ่งมากและ JSON.NET เป็นคำตอบเดียวที่ฉันลองใช้
bnieland

15
ไม่ทำงานหากคุณใช้อาร์เรย์ของคู่ค่าคีย์ใน json [{key: "a", value: "1"}, {key: "b", value:"2"}]คุณต้องทำสิ่งนี้:var dict = JsonConvert.DeserializeObject<List<KeyValuePair<string, string>>>(json);
เอเดรียน

8
ยังใช้งานไม่ได้ถ้าค่าเป็นวัตถุที่ซ้อนกันเพราะ json.net สร้างสิ่งเหล่านั้นเป็น JObjects
Kugel

100

ฉันค้นพบ. NET มีวิธีการสร้างสตริง JSON ในรูปแบบDictionary<String, Object>ผ่านแอสเซมบลีSystem.Web.Script.Serialization.JavaScriptSerializer3.5 ใช้วิธีการSystem.Web.ExtensionsDeserializeObject(String)

ฉันสะดุดเมื่อทำโพสต์ ajax (ผ่าน jquery) ของประเภทเนื้อหา 'application / json' ไปที่. net วิธีหน้าคงที่และเห็นว่าวิธี (ซึ่งมีพารามิเตอร์ประเภทเดียวObject) ได้รับพจนานุกรมนี้อย่างน่าอัศจรรย์


5
แต่ javascriptserializer ในตัวนั้นดีกว่า json.net โซลูชันนั้นดีกว่า ตัวอย่างเช่น javascriptseralizer จะคืนค่า null แทนสตริงว่างและไม่สามารถใช้งานได้กับคุณสมบัติ nullable และอื่น ๆ
pilavdzice

1
@pilavdzice ไม่ต้องพูดถึงความสนุกที่คุณมีเมื่อพยายามแยกวิเคราะห์วันที่เพราะถือว่าเป็นรูปแบบวันที่ที่ไม่ได้มาตรฐานของ MS
พื้นฐาน

16
ตัวอย่างโค้ดแบบย่อ: var jsSerializer = new System.Web.Script.Serialization.JavaScriptSerializer();ตามด้วยDictionary<string, object> dict = (Dictionary<string, object>)jsSerializer.DeserializeObject(jsonString);
Nate Cook

6
ข้อดีของตัวอย่างของ Nate Cook ในกรณีง่าย ๆ คือหลีกเลี่ยงความต้องการ DLLs ภายนอก ฉันกำลังเข้าถึง API จากคอนโซลแบบสแตนด์อโลนที่สามารถพึ่งพา. NET Framework เท่านั้น
Nick.T

@pilavdzice คุณช่วยอธิบายรายละเอียดเพิ่มเติมได้ไหม? ฉันไม่สามารถทำซ้ำสิ่ง "ส่งคืนโมฆะแทนสตริงว่าง" สิ่งนั้นให้ฉันค่าสตริงว่างสำหรับSomeData: ""
34919

51

สำหรับผู้ที่ค้นหาอินเทอร์เน็ตและสะดุดกับโพสต์นี้ฉันเขียนบล็อกโพสต์เกี่ยวกับวิธีใช้คลาส 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 แบบนี้ {"id": "13", "value": true} และสำหรับฉันเท่านั้น Dictionary <dynamic> solution ใช้ได้ผล
Marko

ตกลงฉันพบว่ามันเป็นปัญหาที่ ... คุณต้องเพิ่ม [] หลังจากประกาศพจนานุกรมเพื่อ deserialize อย่างถูกต้อง ... ฉันเพิ่มความคิดเห็นในโพสต์บล็อกของคุณด้วย ... ไชโย;)
Marko

ฉันได้อัปเดตคำตอบเพื่อแสดงชุดข้อมูลเฉพาะของคุณแล้ว มันทำงานได้ดีกับไดนามิก
JP Richardson

ฉันเพิ่งเขียนโปรแกรมวิเคราะห์คำ JSON อีกตัวที่ยืดหยุ่นกว่าเล็กน้อยและรองรับ Silverlight: procbits.com/2011/08/11/…
JP Richardson

41

พยายามที่จะไม่ใช้การใช้งาน JSON ภายนอกใด ๆ ดังนั้นฉันจึง deserialised เช่นนี้:

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);

6
เพิ่ม System.Web.Extensions อ้างอิงเพื่อใช้ System.Web.Script
Patrick Cullen

1
System.Web.Script.Serializationผมชอบคำตอบนี้ดีที่สุดเพราะมันเป็นเรื่องง่ายและใช้สุทธิ มันใช้งานได้ ฉันยังสามารถใช้ JSON ที่ "ไม่ถูกต้อง" string json = "{'id':13, 'value': true}";ได้
สไตล์

จากความอยากรู้อยากเห็นมีวิธีหนึ่งบรรทัดในการยกเลิกการซีเรียลไลซ์ลงในพจนานุกรม OrdinalIgnoreCase หรือไม่
batbaatar

38

ฉันมีปัญหาเดียวกันดังนั้นฉันจึงเขียนสิ่งนี้ด้วยตัวเอง การแก้ปัญหานี้แตกต่างจากคำตอบอื่น ๆ เพราะมันสามารถแบ่งออกเป็นหลายระดับ

เพียงส่งสตริง JSON ไปยังฟังก์ชันdeserializeToDictionaryมันจะส่งคืน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>ถ้าองค์ประกอบเป็นอาร์เรย์

เพียงแค่ส่งสตริง JSON ไปยังฟังก์ชันdeserializeToDictionaryOrListมันจะส่งคืน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;
    }
}

@Jordan ขอบคุณที่ชี้ให้เห็นฉันได้ทำการแก้ไขบางอย่างกับรหัสนี้ แต่ฉันไม่ได้ตอนนี้ รหัสนี้ไม่ได้จัดการวัตถุ JArray ฉันจะอัปเดตรหัสเมื่อมี
Dasun

1
ไม่ใช่ปัญหา. ฉันพูดถึงเพียงเพราะการเรียนรู้เกี่ยวกับisและasผู้ปฏิบัติงานช่วยฉันอย่างมากและทำให้รหัสของฉันง่ายขึ้น
Jordan

มันใช้งานได้ แต่ไม่มีประสิทธิภาพเพราะมันเรียก ToString แล้ว Deserialize อีกครั้ง ดูคำตอบของ Falko ด้านล่าง เป็น deserialize สตริงต้นทางเพียงครั้งเดียว
Sergei Zinovyev

1
คำตอบของ Falko ใช้ได้เฉพาะเมื่อคุณทราบโครงสร้างข้อมูลล่วงหน้า โซลูชันนี้สามารถใช้กับสตริง JSON ใดก็ได้
Dasun

16

หากคุณกำลังใช้วิธีการอ้างอิงแบบไม่มีการอ้างอิงที่มีน้ำหนักเบาบางทีโค้ดที่ฉันเพิ่งเขียนอาจจะใช้งานได้ (ฉันไม่สามารถรับประกันความทนทานได้ 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 แต่ในทางเทคนิคคุณไม่ได้เขียนฉันทำ]


3
นั่นเป็นคำตอบเดียวที่ทำงานกับ Silverlight และไร้การพึ่งพา! Silverlight ไม่มี JavascriptSerializer หรือ Serializable และไม่มีการพึ่งพาหมายความว่าไม่มี Json.NET, RestSharp หรือ MiniJSON @DanCsharpster เท่านั้นที่ลองใช้วิธีแก้ไขปัญหาอื่นที่เป็นไปได้ แต่น่าเสียดายที่มันไม่ได้ผลสำหรับฉันอย่างที่ทำ
Cœur

1
มีอะไรผิดปกติกับการเพิ่มการอ้างอิงถึงสิ่งที่ง่ายเช่น JSON.NET? จำเป็นต้องมีน้ำหนักเบาขนาดนั้นหรือไม่ที่คุณไม่สามารถอ้างอิงอะไรได้ ฉันไม่ได้บอกว่ารหัสของคุณจะไม่ทำงาน แต่ทุกครั้งที่คุณม้วนตัวเองคุณจะเสี่ยงต่อการที่รหัสของคุณไม่แข็งแกร่งสำหรับสิ่งต่าง ๆ เช่นเคสขอบหรือเร็วเท่าห้องสมุดทดสอบอย่าง JSON.NET
Dan Csharpster

1
การกลิ้งของคุณเองเป็นความคิดที่ไม่ดีเมื่อคุณมีทางเลือกที่ดี ฉันรู้ว่าจากสถานการณ์ที่มีจะไม่มีที่มีน้ำหนักเบา และฉันต้องการรหัสที่เหมาะสมน้อยกว่าซึ่งง่ายต่อการอ่านและเปลี่ยนแปลง
Jordan

3
ตอนแรกฉันเขียนโค้ดนั้นเพราะฉันไม่มีทางเลือก พิจารณาสิ่งต่าง ๆ เช่น Silverlight หรือผู้ให้บริการประเภทต่างๆสำหรับผลิตภัณฑ์ Office ที่การเพิ่มการอ้างอิงภายนอกไปยังโครงการนั้นอาจเป็นปัญหาหรือเป็นไปไม่ได้
dexy

ฉันรู้ว่าไม่กี่ปีต่อมา แต่นี่ยังคงเป็นคำถามที่ถูกต้องมาก สำหรับทุกคนที่สงสัยว่าทำไมเราถึงต้องการให้มีน้ำหนักเบามากถ้าคุณทำงานกับ SQL CLR C # มีไลบรารี "ปลอดภัย" จำนวนมากเท่านั้นที่คุณสามารถใช้งานได้และSystem.RunTime.Serializationไม่ใช่หนึ่งในนั้น JSON.NET ขึ้นอยู่กับ มันและดังนั้นจึงไม่สามารถใช้อย่างใดอย่างหนึ่ง ขอบคุณ dexy สำหรับการทำงานที่ดีเยี่ยมของคุณผมกล้าที่จะปรับปรุงมันเล็กน้อยเพื่อให้สามารถ deserialize อาร์เรย์ของอาร์เรย์เห็นรหัสปรับปรุงในคำตอบของฉันที่นี่
Alberto Rechy

15

ฉันแค่ต้องแยกวิเคราะห์พจนานุกรมที่ซ้อนกันเช่น

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


JObject.Parse (json) .ToObject <Dictionary <Guid, List <int> >> () ทำงานให้ฉันในสถานการณ์ของฉันขอบคุณ
geedubb

11

System.Text.Json

ตอนนี้สามารถทำได้โดยใช้System.Text.Jsonสิ่งที่มีอยู่.net core 3.0แล้วภายใน ตอนนี้เป็นไปได้ที่จะแยกแยะ JSON โดยไม่ต้องใช้ห้องสมุดบุคคลที่สาม

var json = @"{""key1"":""value1"",""key2"":""value2""}";
var values = JsonSerializer.Deserialize<Dictionary<string, string>>(json);

ยังมีอยู่ในแพ็คเกจ nu-get System.Text.Jsonหากใช้. Net Standard หรือ. Net Framework


1
ใช่ System.Text.Jsonเป็นวิธีที่จะไปวันนี้
mfluehr

2
ใช่มันดูมีแนวโน้ม! อย่างไรก็ตามโปรดทราบว่า System.Text.Json เวอร์ชันเริ่มต้นของ. NET Core 3.1 ไม่สนับสนุนการแยกพจนานุกรมด้วยคีย์ที่ไม่ใช่สตริง ในขณะที่ OP ของฉันเกี่ยวกับสตริงในทางปฏิบัติตอนนี้ฉันมี Guid keys จำนวนมากดังนั้น "bit" นี้ฉันเมื่อพยายามเปลี่ยน นอกจากนี้ยังไม่มีคุณสมบัติเทียบเท่าบางอย่าง (จำเป็นต้องใช้)
richardtallent

6

Mark Rendle โพสต์นี้เป็นความคิดเห็นฉันต้องการโพสต์เป็นคำตอบเนื่องจากเป็นโซลูชั่นเดียวที่ทำงานมาแล้วเพื่อกลับสู่ความสำเร็จและรหัสข้อผิดพลาดเป็นผลมาจากการตอบสนองของ Google reCaptcha

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

ขอขอบคุณอีกครั้งทำเครื่องหมาย!


1
JavaScriptSerializer เลิกใช้แล้วเกือบ เอกสารบอกว่าเราควรใช้ JSON.NET ( docs.microsoft.com/en-us/dotnet/api/ ...... )
Mario Lopez

ยังเหมาะสำหรับแอปดั้งเดิมที่คุณไม่ต้องการรวมการพึ่งพาเพิ่มเติม
Andrew Grothe

5

แก้ไข: ใช้งานได้ แต่คำตอบที่ยอมรับโดยใช้ 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 ...


2
[TestMethod] โมฆะสาธารณะ TestSimpleObject () {const string json = @ "{" "ชื่อ" ":" "Bob" "," "อายุ" ": 42}"; var dict = new JavaScriptSerializer (). DeserializeObject (json) เป็น IDictionary <string, object>; Assert.IsNotNull (Dict); Assert.IsTrue (dict.ContainsKey ( "ชื่อ")); Assert.AreEqual ("Bob", dict ["ชื่อ"]); Assert.IsTrue (dict.ContainsKey ( "อายุ")); Assert.AreEqual (42, dict ["อายุ"]); }
ทำเครื่องหมาย Rendle

1
มันยอดเยี่ยมมาก ช่วยในการปรับใช้บริการ WCF ที่อินเตอร์เฟสใช้ JSON กับไคลเอนต์ที่ใช้เบราว์เซอร์
Anton

@ Mark Rendle: การใช้งานของคุณนั้นง่ายมากและเป็นสิ่งเดียวที่ได้ผลสำหรับฉันในการได้รับผลสำเร็จและรหัสข้อผิดพลาด json ฉันได้ลองวิธีแก้ปัญหาหลายอย่างแล้วขอบคุณที่โพสต์ข้อความนั้นเป็นความคิดเห็น มันควรจะเป็นคำตอบ
ไบรอัน

5

ฉันได้เพิ่มโค้ดที่ส่งโดย 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;
}

4

ฉันเพิ่มการตรวจสอบค่าว่างใน JSON ให้กับคำตอบอื่น

ฉันมีปัญหาเดียวกันดังนั้นฉันจึงเขียนสิ่งนี้ด้วยตัวเอง การแก้ปัญหานี้แตกต่างจากคำตอบอื่น ๆ เพราะมันสามารถแบ่งออกเป็นหลายระดับ

เพียงส่งสตริง json ในฟังก์ชั่นdeserializeToDictionaryมันจะส่งคืน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>ไลซ์เป็นวัตถุ


1
+1 อย่างที่ฉันพูดกับ Dasun ด้านบน d.Value is JObjectคุณก็สามารถตรวจสอบได้ว่า คุณไม่ต้องผ่านการไตร่ตรองเพื่อตรวจสอบประเภท และด้วยisโอเปอเรเตอร์คุณไม่จำเป็นต้องตรวจสอบค่าว่าง มันจะส่งกลับเท็จถ้าวัตถุเป็นโมฆะ
Jordan

3

ดูเหมือนว่าคำตอบทั้งหมดเหล่านี้ที่นี่เพียงแค่สมมติว่าคุณสามารถดึงสายเล็ก ๆ ออกมาจากวัตถุที่ใหญ่กว่า ... สำหรับผู้ที่ต้องการกำจัดวัตถุขนาดใหญ่ด้วยพจนานุกรมเช่นนี้ในที่ใดที่หนึ่งในแผนที่และผู้ที่ใช้ 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 เป็นประเภทใด ๆ ที่ไม่ทำการทำการ deserialize อย่างถูกต้อง

เรียกง่าย ๆ ว่า:

MyObjtype newObj = JsonSurrogate.Deserialize<MyObjtype>(jsonStr, encoding);

โปรดทราบว่าด้วยเหตุผลบางอย่างสิ่งนี้มีปัญหาในการใช้สตริงคีย์ซึ่งมีช่องว่าง พวกเขาไม่ได้อยู่ในรายการสุดท้าย อาจเป็นไปได้ว่ามันเป็นเพียงแค่รายละเอียดของ json และ api ที่ฉันโทรหานั้นถูกนำไปใช้งานไม่ดี ไม่รู้สินะ. อย่างไรก็ตามฉันแก้ไขได้โดยการแทนที่ regex ด้วยการขีดเส้นใต้ในข้อมูล json ดิบและแก้ไขพจนานุกรมหลังจากการดีซีเรียลไลเซชัน


โดยวิธีการที่แปลกประหลาดบางอย่างโมโนดูเหมือนว่ามีปัญหาในการใช้สิ่งนี้ ...
Nyerguds

ขอขอบคุณที่แบ่งปัน แต่น่าเสียดายที่โซลูชันนี้ไม่สนับสนุนประเภทที่ไม่ใช่แบบดั้งเดิมและไม่มีวิธีรับค่าดิบดังนั้นคุณจึงสามารถสร้างมันขึ้นมาเองได้ ถ้าฉันลงทะเบียนประเภทที่กำหนดเองของฉันใน KnownTypes และใช้ในพจนานุกรมมันจะเรียกพจนานุกรมก่อนฉันคาดว่ามันจะเริ่มการแยกวิเคราะห์จากล่างขึ้นบนจากประเภทระยะไกลที่สุดไปยังประเภทที่ซับซ้อนกว่า
Ivan Leonenko

คำถามที่ถามถึงDictionary<String,String>เท่านั้น ฉันไม่เคยลองกำจัดความซับซ้อนประเภทที่ซับซ้อนด้วยระบบนี้
Nyerguds

3

ตามความคิดเห็นข้างต้นลอง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);

ดูเหมือนว่าจะทำงานได้แม้กับวัตถุและรายการที่ซับซ้อน


1

ฉันเพียงแค่ดำเนินการใน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 ที่คุณคาดหวัง - ในกรณีของฉันฉันได้รับวัตถุเดียวที่มีคุณสมบัติหลายอย่าง ในลิงค์ที่แนบผู้เขียนกำลังเรียกรายการ


1

วิธีการของฉัน deserializes โดยตรงกับ 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;
    }
}


1

เกมช้าไปหน่อย แต่ไม่ใช่วิธีการแก้ปัญหาข้างต้นชี้ให้ฉันเห็นว่าในทิศทางของ. NET ที่เรียบง่ายและบริสุทธิ์ไม่มีวิธีแก้ปัญหา json.net ดังนั้นที่นี่มันเป็นง่ายมาก ด้านล่างเป็นตัวอย่างการรันเต็มรูปแบบของการทำให้เป็นอนุกรมมาตรฐาน. NET Json ตัวอย่างมีพจนานุกรมทั้งในวัตถุรากและในวัตถุลูก

สัญลักษณ์สีทองคือแมวตัวนี้วิเคราะห์การตั้งค่าเป็นพารามิเตอร์ตัวที่สองของ serializer:

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);
                        }
                    }
                }
            }
        }
    }

0

น่ารำคาญพอหากคุณต้องการใช้ตัวประสานโมเดลเริ่มต้นดูเหมือนว่าคุณจะต้องใช้ค่าดัชนีตัวเลขเช่นแบบฟอร์ม POST

ดูข้อความที่ตัดตอนมาต่อไปนี้จากบทความนี้http://msdn.microsoft.com/en-us/magazine/hh781022.aspx :

แม้ว่าจะค่อนข้างใช้งานง่าย แต่คำขอ JSON นั้นมีข้อกำหนดเหมือนกัน แต่ต้องปฏิบัติตามรูปแบบการตั้งชื่อโพสต์ไวยากรณ์ ยกตัวอย่างเช่น 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
}

สถานการณ์การรวบรวมวัตถุที่ซับซ้อนอาจเป็นหนึ่งในสถานการณ์ที่มีปัญหาอย่างกว้างขวางที่สุดที่นักพัฒนาเรียกใช้เนื่องจากไวยากรณ์ไม่จำเป็นต้องชัดเจนสำหรับนักพัฒนาทั้งหมด อย่างไรก็ตามเมื่อคุณเรียนรู้ไวยากรณ์ที่ค่อนข้างง่ายสำหรับการโพสต์คอลเลกชันที่ซับซ้อนสถานการณ์เหล่านี้กลายเป็นเรื่องง่ายที่จะจัดการกับ


0

ฉันขอแนะนำให้ใช้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);

serializer ถูกกำหนดไว้ที่ไหน?
bnieland

.. และ Category3MeasureModel คืออะไร? ไม่มีความนิยมใน Google
bnieland

1
นั่นเป็นเพียงคลาสโมเดลที่ฉันซีเรียลไลซ์สำหรับโครงการของฉัน มันควรจะเป็นคลาส Foo แต่ฉัน recopied ทั้งส่วนจากรหัสการผลิต คุณควรสร้างของคุณเองเช่นคลาส Foo ของฉัน ฉันเปลี่ยนชื่อเป็นฟูเพื่อให้ง่ายขึ้น เป็นเพียงคลาสของคุณสมบัติหรือเขตข้อมูลที่คุณต้องการต่อเนื่องเป็น json และย้อนกลับ
Dan Csharpster

1
@DanCsharpster ด้วยการคัดลอกรหัสที่แน่นอนของฉันฉันได้รับบน Windows Phone 8.1 Silverlight: `ข้อยกเว้นประเภท 'System.Security.SecurityException' เกิดขึ้นใน System.ServiceModel.Web.ni.dll แต่ไม่มีการจัดการในผู้ใช้ รหัสข้อมูลเพิ่มเติม: ประเภทสัญญาข้อมูล 'MyApp.Foo' ไม่สามารถทำการดีซีเรียลไลซ์ได้เนื่องจากสมาชิก 'Data' ไม่ได้เป็นสาธารณะ การทำให้สมาชิกเป็นแบบสาธารณะจะแก้ไขข้อผิดพลาดนี้ได้ หรือคุณสามารถทำให้มันภายในและการใช้แอตทริบิวต์ InternalsVisibleToAttribute ในการชุมนุมของคุณเพื่อให้เป็นอันดับสมาชิกภายใน
Cœur

1
@DanCsharpster และเมื่อเปลี่ยนข้อมูลคุณสมบัติเป็นสมาชิก (ไม่ได้รับ; set;) ฉันจะได้รับ: มีข้อยกเว้นโอกาสแรกของประเภท 'System.ArgumentException' เกิดขึ้นใน System.ServiceModel.Web.ni.dll ข้อมูลเพิ่มเติม: วัตถุของ ไม่สามารถแปลงประเภท 'System.Object' เป็นประเภท 'System.Collections.Generic.Dictionary`2 [System.String, System.String]'
Cœur

0

สำหรับผู้ที่พยายามแปลง JSON เป็นพจนานุกรมเพียงเพื่อดึงค่าบางอย่างออกมา มีวิธีง่ายๆในการใช้Newtongsoft.JSON

using Newtonsoft.Json.Linq
...

JObject o = JObject.Parse(@"{
  'CPU': 'Intel',
  'Drives': [
    'DVD read/writer',
    '500 gigabyte hard drive'
  ]
}");

string cpu = (string)o["CPU"];
// Intel

string firstDrive = (string)o["Drives"][0];
// DVD read/writer

IList<string> allDrives = o["Drives"].Select(t => (string)t).ToList();
// DVD read/writer
// 500 gigabyte hard drive
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.