การดีซีเรียลไลซ์ข้อมูล JSON เป็น C # โดยใช้ JSON.NET


144

ฉันค่อนข้างใหม่ในการทำงานกับ C # และข้อมูล JSON และกำลังมองหาแนวทาง ฉันใช้ C # 3.0 กับ. NET 3.5SP1 และ JSON.NET 3.5r6

ฉันมีคลาส C # ที่กำหนดไว้ซึ่งฉันต้องการเติมจากโครงสร้าง JSON อย่างไรก็ตามโครงสร้าง JSON บางรายการสำหรับรายการที่ดึงจากเว็บเซอร์วิสจะมีแอตทริบิวต์ที่เป็นไปได้ทั้งหมดที่กำหนดไว้ในคลาส C #

ฉันกำลังทำสิ่งที่ดูเหมือนจะผิดวิธีที่ยากและเพิ่งเลือกแต่ละค่าหนึ่งโดยหนึ่งจาก JObject และเปลี่ยนสายอักขระเป็นคุณสมบัติคลาสที่ต้องการ

JsonSerializer serializer = new JsonSerializer();
var o = (JObject)serializer.Deserialize(myjsondata);

MyAccount.EmployeeID = (string)o["employeeid"][0];

วิธีที่ดีที่สุดในการดีซีเรียลไลซ์โครงสร้าง JSON ลงในคลาส C # และการจัดการข้อมูลที่ขาดหายไปที่เป็นไปได้จากแหล่ง JSON คืออะไร

คลาสของฉันถูกกำหนดเป็น:

  public class MyAccount
  {

    [JsonProperty(PropertyName = "username")]
    public string UserID { get; set; }

    [JsonProperty(PropertyName = "givenname")]
    public string GivenName { get; set; }

    [JsonProperty(PropertyName = "sn")]
    public string Surname { get; set; }

    [JsonProperty(PropertyName = "passwordexpired")]
    public DateTime PasswordExpire { get; set; }

    [JsonProperty(PropertyName = "primaryaffiliation")]
    public string PrimaryAffiliation { get; set; }

    [JsonProperty(PropertyName = "affiliation")]
    public string[] Affiliation { get; set; }

    [JsonProperty(PropertyName = "affiliationstatus")]
    public string AffiliationStatus { get; set; }

    [JsonProperty(PropertyName = "affiliationmodifytimestamp")]
    public DateTime AffiliationLastModified { get; set; }

    [JsonProperty(PropertyName = "employeeid")]
    public string EmployeeID { get; set; }

    [JsonProperty(PropertyName = "accountstatus")]
    public string AccountStatus { get; set; }

    [JsonProperty(PropertyName = "accountstatusexpiration")]
    public DateTime AccountStatusExpiration { get; set; }

    [JsonProperty(PropertyName = "accountstatusexpmaxdate")]
    public DateTime AccountStatusExpirationMaxDate { get; set; }

    [JsonProperty(PropertyName = "accountstatusmodifytimestamp")]
    public DateTime AccountStatusModified { get; set; }

    [JsonProperty(PropertyName = "accountstatusexpnotice")]
    public string AccountStatusExpNotice { get; set; }

    [JsonProperty(PropertyName = "accountstatusmodifiedby")]
    public Dictionary<DateTime, string> AccountStatusModifiedBy { get; set; }

    [JsonProperty(PropertyName = "entrycreatedate")]
    public DateTime EntryCreatedate { get; set; }

    [JsonProperty(PropertyName = "entrydeactivationdate")]
    public DateTime EntryDeactivationDate { get; set; }

  }

และตัวอย่างของการแยกวิเคราะห์ JSON คือ:

{
    "givenname": [
        "Robert"
    ],
    "passwordexpired": "20091031041550Z",
    "accountstatus": [
        "active"
    ],
    "accountstatusexpiration": [
        "20100612000000Z"
    ],
    "accountstatusexpmaxdate": [
        "20110410000000Z"
    ],
    "accountstatusmodifiedby": {
        "20100214173242Z": "tdecker",
        "20100304003242Z": "jsmith",
        "20100324103242Z": "jsmith",
        "20100325000005Z": "rjones",
        "20100326210634Z": "jsmith",
        "20100326211130Z": "jsmith"
    },
    "accountstatusmodifytimestamp": [
        "20100312001213Z"
    ],
    "affiliation": [
        "Employee",
        "Contractor",
        "Staff"
    ],
    "affiliationmodifytimestamp": [
        "20100312001213Z"
    ],
    "affiliationstatus": [
        "detached"
    ],
    "entrycreatedate": [
        "20000922072747Z"
    ],
    "username": [
        "rjohnson"
    ],
    "primaryaffiliation": [
        "Staff"
    ],
    "employeeid": [
        "999777666"
    ],
    "sn": [
        "Johnson"
    ]
}

คำตอบ:


277

ใช้

var rootObject =  JsonConvert.DeserializeObject<RootObject>(string json);

สร้างคลาสของคุณบนJSON 2 C #


เอกสารประกอบ Json.NET: การทำให้เป็นอันดับและการเลิกทำการ JSON ด้วย Json.NET


32
Visual Studio ยังมีตัวเลือก Paste JSON เป็น Classes ในเมนู Edit-Paste Special
Jonathan Allen

76

คุณได้ลองใช้วิธี DeserializeObject ทั่วไปแล้วหรือยัง?

JsonConvert.DeserializeObject<MyAccount>(myjsondata);

เขตข้อมูลใด ๆ ที่ขาดหายไปในข้อมูล JSON ควรเป็นค่า NULL

UPDATE:

ถ้าสตริง JSON เป็นอาร์เรย์ลองสิ่งนี้:

var jarray = JsonConvert.DeserializeObject<List<MyAccount>>(myjsondata);

jarrayList<MyAccount>แล้วควรจะเป็น

การอัปเดตอีกครั้ง:

ข้อยกเว้นที่คุณได้รับไม่สอดคล้องกับอาร์เรย์ของวัตถุ - ฉันคิดว่า serializer มีปัญหากับaccountstatusmodifiedbyคุณสมบัติการพิมพ์พจนานุกรมของคุณ

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

เอกสารประกอบ: การทำให้เป็นอันดับและการเลิกทำการ JSON ด้วย Json.NET


ขอบคุณ อย่างไรก็ตามฉันได้รับข้อผิดพลาดของ "ไม่สามารถทำการเรียงลำดับอาร์เรย์ JSON ลงในประเภท 'System.String' ได้" เมื่อพยายาม deserialize (ตัวอย่าง) อาร์เรย์ JSON givenname ลงในสตริงคลาส GivenName คุณลักษณะ JSON ที่ฉันได้กำหนดเป็นสตริงในคลาส C # เป็นเพียงอาร์เรย์องค์ประกอบเดียวที่เคย นี่คือเหตุผลที่ฉันเริ่มเลือกค่าหนึ่งโดยหนึ่งในขณะที่ฉันวิ่งเข้าไปในปัญหาประเภทนี้ในระหว่างกระบวนการดีซีเรียลไลซ์ เวทมนตร์อื่น ๆ ที่ฉันสามารถมองเห็นได้?

ดังนั้น ... DateTime AccountStatusExpiration(ตัวอย่าง) ไม่สามารถลบล้างได้ตามที่กำหนดไว้ในรหัส สิ่งที่ต้องใช้เพื่อทำให้เป็นโมฆะ? เปลี่ยนDateTimeเป็นDateTime??
Hamish Grubijan

50

คำตอบทำซ้ำจากhttps://stackoverflow.com/a/10718128/776476

คุณสามารถใช้dynamicประเภทC # เพื่อทำให้สิ่งต่าง ๆ ง่ายขึ้น เทคนิคนี้ยังทำให้การแฟ็กเตอริ่งทำได้ง่ายขึ้นโดยไม่ต้องพึ่งพาสายเวทย์

json

jsonสตริงดังต่อไปนี้คือการตอบสนองอย่างง่ายจากการโทร http API และจะกำหนดคุณสมบัติที่สอง: และIdName

{"Id": 1, "Name": "biofractal"}

ค#

ใช้JsonConvert.DeserializeObject<dynamic>()ในการแยกแยะสตริงนี้เป็นชนิดไดนามิกจากนั้นเข้าถึงคุณสมบัติได้ตามปกติ

var results = JsonConvert.DeserializeObject<dynamic>(json);
var id = results.Id;
var name= results.Name;

หมายเหตุ : การเชื่อมโยง NuGet สำหรับ NewtonSoft ชุมนุมhttp://nuget.org/packages/newtonsoft.json อย่าลืมเพิ่ม: using Newtonsoft.Json;เพื่อเข้าชั้นเรียนเหล่านั้น


7
รักการใช้ <dynamic> อย่างไรก็ตามฉันต้องทำสิ่งนี้เพื่อให้มันใช้งานได้: ผลลัพธ์ ["Id"] คุณค่าและผลลัพธ์ ["ชื่อ"] ค่า
fredw

1
แม้ว่าไดนามิกเป็นทางเลือกที่ดีตัวอย่างข้างต้นไม่ได้ใช้ 'สตริงมายากล' แต่แทนที่จะใช้ชื่อสามัญที่พิมพ์อย่างรุนแรงซึ่งได้รับการอัปเดตระหว่างเทคนิคการรีแฟคเตอร์ VS ปกติ (ยกเว้นในมุมมองใน MVC ซึ่งอยู่นอกขอบเขตของคำถามนี้)
gcoleman0828

4
คุณยังมี 'สายเวท' ตอนนี้พวกมันก็ถูกซ่อนไว้โดยการใช้พลัง!
Ian Ringrose

อันที่จริงแล้ว biofractal ทำให้มันกลับมาเป็น "สายเวทมนตร์" ตามที่ @ IanRingrose ชี้ให้เห็น วัตถุแบบไดนามิกที่ส่งกลับโดยDeserializeObject<dynamic>เป็นคำจำกัดความไม่ "ตรวจสอบประเภท" ดังนั้นบรรทัดต่อไปนี้results.Idและresults.Nameไม่สามารถตรวจสอบได้ในเวลารวบรวม ข้อผิดพลาดใด ๆ จะเกิดขึ้นในเวลาทำงานแทน DeserializeObject<List<MyAccount>>คมชัดนี้ด้วยการเรียกขอพิมพ์เช่น การอ้างอิงถึงคุณสมบัติเหล่านั้นสามารถยืนยันได้ในเวลารวบรวม การใช้งานdynamicถึงแม้ว่ามันอาจจะสะดวก แต่แนะนำ "magic strings" เป็นชื่อคุณสมบัติ การลดความทนทานของ IMHO
ToolmakerSteve

8

คุณสามารถใช้ได้:

JsonConvert.PopulateObject(json, obj);

ที่นี่: jsonเป็นสตริง json objเป็นวัตถุเป้าหมาย ดูตัวอย่าง

หมายเหตุ: PopulateObject()จะไม่ลบข้อมูลรายการ obj หลังจากPopulate()นั้นobj'sสมาชิกรายการจะมีข้อมูลดั้งเดิมและข้อมูลจากสตริง json


2
it PopulateObject - Populate ไม่ได้อยู่ในโมเดลวัตถุ
amok

1
สิ่งนี้ทำงานได้สมบูรณ์แบบสำหรับฉัน! ฉันกำลังมีปัญหาที่ฉันมีสตริง JSON ที่ค่อนข้างซับซ้อนเมื่อฉันพยายามโยนมันไปยังวัตถุ C # สิ่งใดที่ทำเครื่องหมายเป็น 'NotNull' จะหายไปจากวัตถุแม้ว่าจะมีอยู่ในสตริง JSON เพื่อเริ่มต้นด้วย ที่แปลกมาก. ฉันใช้วิธีนี้และทำงานได้สมบูรณ์แบบ!
jward01

3

สร้างขึ้นจากคำตอบของ bbant นี่เป็นโซลูชันที่สมบูรณ์แบบของฉันสำหรับการเลิกทำการ JSON จาก URL ระยะไกล

using Newtonsoft.Json;
using System.Net.Http;

namespace Base
{
    public class ApiConsumer<T>
    {
        public T data;
        private string url;

        public CalendarApiConsumer(string url)
        {
            this.url = url;
            this.data = getItems();
        }

        private T getItems()
        {
            T result = default(T);
            HttpClient client = new HttpClient();

            // This allows for debugging possible JSON issues
            var settings = new JsonSerializerSettings
            {
                Error = (sender, args) =>
                {
                    if (System.Diagnostics.Debugger.IsAttached)
                    {
                        System.Diagnostics.Debugger.Break();
                    }
                }
            };

            using (HttpResponseMessage response = client.GetAsync(this.url).Result)
            {
                if (response.IsSuccessStatusCode)
                {
                    result = JsonConvert.DeserializeObject<T>(response.Content.ReadAsStringAsync().Result, settings);
                }
            }
            return result;
        }
    }
}

การใช้งานจะเป็นเช่น:

ApiConsumer<FeedResult> feed = new ApiConsumer<FeedResult>("http://example.info/feeds/feeds.aspx?alt=json-in-script");

FeedResultคลาสที่สร้างโดยใช้Xamasoft JSON Class Generatorอยู่ที่ไหน

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

ตัวสร้างคลาส Xamasoft JSON


1

ฉันพบว่าฉันสร้างวัตถุของฉันไม่ถูกต้อง ฉันใช้http://json2csharp.com/เพื่อสร้างคลาสวัตถุของฉันจาก JSON เมื่อฉันมี Oject ที่ถูกต้องฉันก็สามารถส่งโดยไม่มีปัญหา Norbit ผิด Noob คิดว่าฉันจะเพิ่มในกรณีที่คุณมีปัญหาเดียวกัน


1

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

รหัสต่อไปนี้ถูกสร้างขึ้นด้วยวิธีการแบบไดนามิกในใจ

dynObj = (JArray) JsonConvert.DeserializeObject(nvm);

foreach(JObject item in dynObj) {
 foreach(JObject trend in item["trends"]) {
  Console.WriteLine("{0}-{1}-{2}", trend["query"], trend["name"], trend["url"]);
 }
}

รหัสนี้ช่วยให้คุณเข้าถึงสมาชิกที่มีอยู่ในสตริง Json เป็นวิธีที่แตกต่างโดยไม่จำเป็นต้องเรียน query, trendและurlเป็นวัตถุที่มีอยู่ในสตริง JSON

คุณสามารถใช้เว็บไซต์นี้ได้ อย่าไว้ใจชั้นเรียน 100% แต่คุณจะได้รับความคิด


0

สมมติว่าข้อมูลตัวอย่างของคุณถูกต้อง givenname ของคุณและรายการอื่น ๆ ที่อยู่ในวงเล็บเป็นอาร์เรย์ใน JS ... คุณจะต้องการใช้รายการสำหรับชนิดข้อมูลเหล่านั้น และ List for say accountstatusexpmaxdate ... ฉันคิดว่าตัวอย่างของคุณมีวันที่ในรูปแบบที่ไม่ถูกต้อง

นี่เป็นโพสต์เก่า แต่ต้องการจดบันทึกปัญหา

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.