การดีซีเรียลไลซ์วัตถุ JSON เป็น. NET โดยใช้ Newtonsoft (หรืออาจจะเป็น LINQ ถึง JSON)


318

ฉันรู้ว่ามีบางโพสต์เกี่ยวกับ Newtonsoft ดังนั้นหวังว่านี่ไม่ใช่การทำซ้ำอย่างแน่นอน ... ฉันพยายามแปลงข้อมูล JSON ที่ส่งคืนโดย Kazaa API เป็นวัตถุที่ดีในบางประเภท

WebClient client = new WebClient();
Stream stream = client.OpenRead("http://api.kazaa.com/api/v1/search.json?q=muse&type=Album");
StreamReader reader = new StreamReader(stream);

List<string> list = Newtonsoft.Json.JsonConvert.DeserializeObject<List<string>>(reader.Read().ToString());

foreach (string item in list)
{
    Console.WriteLine(item);
}

//Console.WriteLine(reader.ReadLine());
stream.Close();

นั่นคือ JsonConvert บรรทัดล่าสุดที่ฉันพยายาม ... ฉันไม่ได้รับมันและหวังว่าจะกำจัดฟุตเวิร์กโดยถามพวกคุณ ตอนแรกฉันพยายามแปลงมันเป็นพจนานุกรมหรืออะไรบางอย่าง ... และที่จริงแล้วฉันแค่ต้องการขัดขวางค่าบางอย่างในเอกสารเพื่อพิจารณาจากเอกสารบางที LINT ของ Newtonsoft เป็น JSON อาจเป็นทางเลือกที่ดีกว่า ความคิด / Links?

นี่คือตัวอย่างของข้อมูลการส่งคืน JSON:

{
  "page": 1,
  "total_pages": 8,
  "total_entries": 74,
  "q": "muse",
  "albums": [
    {
      "name": "Muse",
      "permalink": "Muse",
      "cover_image_url": "http://image.kazaa.com/images/69/01672812 1569/Yaron_Herman_Trio/Muse/Yaron_Herman_Trio-Muse_1.jpg",
      "id": 93098,
      "artist_name": "Yaron Herman Trio"
    },
    {
      "name": "Muse",
      "permalink": "Muse",
      "cover_image_url": "htt p://image.kazaa.com/images/54/888880301154/Candy_Lo/Muse/Candy_Lo-Muse_1.jpg",
      "i d": 102702,
      "artist_name": "\u76e7\u5de7\u97f3"
    },
    {
      "name": "Absolution",
      "permalink": " Absolution",
      "cover_image_url": "http://image.kazaa.com/images/65/093624873365/Mus e/Absolution/Muse-Absolution_1.jpg",
      "id": 48896,
      "artist_name": "Muse"
    },
    {
      "name": "Ab solution",
      "permalink": "Absolution-2",
      "cover_image_url": "http://image.kazaa.com/i mages/20/825646911820/Muse/Absolution/Muse-Absolution_1.jpg",
      "id": 118573,
      "artist _name": "Muse"
    },
    {
      "name": "Black Holes And Revelations",
      "permalink": "Black-Holes-An d-Revelations",
      "cover_image_url": "http://image.kazaa.com/images/66/093624428466/ Muse/Black_Holes_And_Revelations/Muse-Black_Holes_And_Revelations_1.jpg",
      "id": 48813,
      "artist_name": "Muse"
    },
    {
      "name": "Black Holes And Revelations",
      "permalink": "Bla ck-Holes-And-Revelations-2",
      "cover_image_url": "http://image.kazaa.com/images/86/ 825646911486/Muse/Black_Holes_And_Revelations/Muse-Black_Holes_And_Revelations_1 .jpg",
      "id": 118543,
      "artist_name": "Muse"
    },
    {
      "name": "Origin Of Symmetry",
      "permalink": "Origin-Of-Symmetry",
      "cover_image_url": "http://image.kazaa.com/images/29/825646 912629/Muse/Origin_Of_Symmetry/Muse-Origin_Of_Symmetry_1.jpg",
      "id": 120491,
      "artis t_name": "Muse"
    },
    {
      "name": "Showbiz",
      "permalink": "Showbiz",
      "cover_image_url": "http: //image.kazaa.com/images/68/825646182268/Muse/Showbiz/Muse-Showbiz_1.jpg",
      "id": 60444,
      "artist_name": "Muse"
    },
    {
      "name": "Showbiz",
      "permalink": "Showbiz-2",
      "cover_imag e_url": "http://image.kazaa.com/images/50/825646912650/Muse/Showbiz/Muse-Showbiz_ 1.jpg",
      "id": 118545,
      "artist_name": "Muse"
    },
    {
      "name": "The Resistance",
      "permalink": "T he-Resistance",
      "cover_image_url": "http://image.kazaa.com/images/36/825646864836/ Muse/The_Resistance/Muse-The_Resistance_1.jpg",
      "id": 121171,
      "artist_name": "Muse"
    }
  ],
  "per_page": 10
}

ฉันทำการอ่านเพิ่มเติมและพบว่า LINQT ของ Newtonsoft ต่อ JSON เป็นสิ่งที่ฉันต้องการ ... โดยใช้ WebClient, Stream, StreamReader และ Newtonsoft ... ฉันสามารถกด Kazaa สำหรับข้อมูล JSON ดึง URL ดาวน์โหลดไฟล์และทำ ทั้งหมดในเหมือนเจ็ดบรรทัดของรหัส! ฉันรักมัน.

WebClient client = new WebClient();
Stream stream = client.OpenRead("http://api.kazaa.com/api/v1/search.json?q=muse&type=Album");
StreamReader reader = new StreamReader(stream);

Newtonsoft.Json.Linq.JObject jObject = Newtonsoft.Json.Linq.JObject.Parse(reader.ReadLine());

// Instead of WriteLine, 2 or 3 lines of code here using WebClient to download the file
Console.WriteLine((string)jObject["albums"][0]["cover_image_url"]);
stream.Close();

โพสต์นี้ได้รับความนิยมมากมายฉันคิดว่ามันอาจมีประโยชน์หากรวมบิต "ใช้" ที่กล่าวถึงในความคิดเห็น

using(var client = new WebClient())
using(var stream = client.OpenRead("http://api.kazaa.com/api/v1/search.json?q=muse&type=Album"))
using (var reader = new StreamReader(stream))
{
    var jObject = Newtonsoft.Json.Linq.JObject.Parse(reader.ReadLine());
    Console.WriteLine((string) jObject["albums"][0]["cover_image_url"]);
}

6
ตัวอย่างเนียนขอบคุณ เพียงแค่ข้อเสนอแนะ: คุณอาจจะทิ้งไปนี้ระยะเวลาสั้น ๆ แต่ตั้งแต่ WebClient, StreamและStreamReaderทั้งหมดใช้IDisposableคุณอาจต้องการที่จะเพิ่มบางusingบล็อกรหัสของคุณ
arcain

อ่าใช่โทรดี ... (ใช่แล้วนี่เป็นเพียงแค่แอปคอนโซลที่ฉันใช้งานได้อย่างรวดเร็วจริง ๆ ในการวิจัยสำหรับงานที่ฉันกำลังทำอยู่) ออกไปวิจัยชิ้นส่วนสุดท้ายของปริศนาการเข้ารหัส HLS + AES :) ... lol
J Benjamin

1
+1 ขอบคุณที่โพสต์ตัวอย่าง Linq สิ่งที่ฉันต้องการ
Mark Wilkins

โซลูชัน newtonsoft นั้นไม่เลิกใช้ JSON ทั้งหมดเช่นกันหรือไม่? เช่นเดียวกับวิธีการแก้ปัญหาของ @ arcain
AXMIM

สังเกตลิงค์ได้ที่นี่: LINQ ถึง JSON
yu yang Jian

คำตอบ:


259

หากคุณต้องการรับไอเท็มบางอย่างจากออบเจ็กต์ JSON ฉันจะใช้ LINQ ของ Json.NET กับJObjectคลาสJSON ตัวอย่างเช่น:

JToken token = JObject.Parse(stringFullOfJson);

int page = (int)token.SelectToken("page");
int totalPages = (int)token.SelectToken("total_pages");

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

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


1
ยาฉันได้ทำการอ่านและทดสอบเพิ่มอีกนิด ... พบว่านี่เป็นวิธีที่ดีในการทำเช่นนั้น ... Newtonsoft ห้องสมุดที่ดีงามฉันจะโพสต์ตัวอย่างของฉันให้คนอื่น
J Benjamin

1
โพสต์ตัวอย่างคร่าวๆของวิธีการที่ฉันทำมัน ... ไม่เหมือนกันฉันเห็นคุณแนะนำ JToken.Parse ... ไม่แน่ใจในความแตกต่างระหว่างทั้งสอง แต่ YA สิ่งที่ดี!
J Benjamin

1
@Jbenjamin ขอบคุณ! นั่นคือการพิมพ์ผิด JToken เป็นคลาสพื้นฐานสำหรับ JObject และเป็นเพียงความชอบส่วนตัวของฉันที่จะทำงานกับประเภทนามธรรมมากขึ้น ขอบคุณที่โทรหาฉัน
arcain

ขออภัย แต่ควรเป็น JToken หรือ JObject? รหัสข้างต้นยังคงทิ้งข้อผิดพลาด "เกิดข้อผิดพลาดในการอ่าน JObject จาก JsonReader" ทุก ๆ ตอนแล้ว
TYRONEMICHAEL

1
@Therone แน่นอนว่าไม่มีปัญหา ฉันใช้รหัสนี้สำหรับการแยกวิเคราะห์สถานะของ Twitter ด้วยเช่นกันและฉันต้องเขียนข้อผิดพลาดเล็กน้อยเกี่ยวกับการโทรไปยัง Twitter เนื่องจากพวกเขาอาจไม่แน่นอนในบางครั้ง หากคุณยังไม่ได้ทำเช่นนั้นฉันขอแนะนำให้ทิ้งการตอบสนอง JSON แบบดิบจาก Twitter ไปยังบันทึกก่อนที่จะพยายามแยกวิเคราะห์ จากนั้นถ้ามันล้มเหลวคุณอย่างน้อยสามารถดูว่าคุณได้รับบางสิ่งบางอย่างที่ขี้ขลาดกว่าสาย
arcain

272

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

JSON

สตริง JSON ด้านล่างคือการตอบสนองที่เรียบง่ายจากการเรียก API HTTP และกำหนดสองคุณสมบัติ: และIdName

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

ค#

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

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

หากคุณระบุประเภทของresultsตัวแปรเป็นdynamicแทนที่จะใช้varคำหลักค่าคุณสมบัติจะยกเลิกการจัดตำแหน่งอย่างถูกต้องเช่นIdไปintและไม่ใช่JValue(ขอบคุณ GFoley83 สำหรับความคิดเห็นด้านล่าง)

หมายเหตุ : การเชื่อมโยง NuGet สำหรับ Newtonsoft ชุมนุมhttp://nuget.org/packages/newtonsoft.json

แพ็คเกจ : คุณยังสามารถเพิ่มแพ็คเกจด้วยโปรแกรมติดตั้ง live nuget โดยที่โครงการของคุณเปิดเพียงแค่เรียกดูแพ็คเกจแล้วติดตั้งติดตั้งถอนการติดตั้งอัปเดตมันจะถูกเพิ่มลงในโครงการของคุณภายใต้ Dependencies / NuGet


ฉันใช้โค้ดเดียวกันกับข้างบนเพื่อยกเลิกการตอบสนอง twitter กับ newtonsoft.dll รุ่น 4.5.6 และมันก็ทำงานได้ดี .. แต่หลังจากอัปเดตเป็นเวอร์ชั่น 5.0.6 .. มันเริ่มโยนข้อผิดพลาด ... ความคิดใด ๆ ทำไม
Pranav

1
ดีสำหรับวัตถุแบบไดนามิกเมื่อเรารู้หรือเรามีคลาส c # เพื่อให้เราสามารถใช้เป็นคลาส C # แทนการเปลี่ยนแบบไดนามิกเช่น <Myclass>
MSTdev

2
ใช้dynamic results = JsonConvert.DeserializeObject<ExpandoObject>(json);ที่นี่ FTW มันถูกต้องจะ deserialize Idเป็น int JValueและไม่ได้เป็น ดูที่นี่: dotnetfiddle.net/b0WxGJ
GFoley83

@biofractal ฉันจะทำสิ่งนี้dynamic results = JsonConvert.DeserializeObject<dynamic>(json); ใน VB.NET ได้อย่างไร Dim results As Object = Newtonsoft.Json.JsonConvert.DeserializeObject(Of Object)(json)ไม่ทำงาน, ไม่เป็นผล.
Flo

@ ลองใช้... DeserializeObject (ของ System.Dynamic . ขยายoObject )
ToolmakerSteve

41

ด้วยdynamicคำหลักมันจะกลายเป็นเรื่องง่ายที่จะแยกวิเคราะห์วัตถุประเภทนี้:

dynamic x = Newtonsoft.Json.JsonConvert.DeserializeObject(jsonString);
var page = x.page;
var total_pages = x.total_pages
var albums = x.albums;
foreach(var album in albums)
{
    var albumName = album.name;

    // Access album data;
}

ฉันอยากรู้วิธีวนลูปผ่านผลลัพธ์และมันใช้เวลานานเกินไปในการค้นหา ... ขอบคุณ !!
batoutofhell

22

แก้ไขให้ถูกต้องหากฉันเข้าใจผิด แต่ตัวอย่างก่อนหน้านี้ฉันเชื่อว่าไม่ตรงกันกับห้องสมุด Json.NET ของ James Newton รุ่นล่าสุด

var o = JObject.Parse(stringFullOfJson);
var page = (int)o["page"];
var totalPages = (int)o["total_pages"];

1
ขอบคุณสำหรับคำตอบของคุณ Rick, ya ที่มีลักษณะคล้ายกับตัวอย่างที่ฉันพบในเอกสารล่าสุดเช่นกัน
J Benjamin

1
ใช่เนื่องจาก arcain ได้แก้ไขคำที่พิมพ์ผิดตอนนี้ความคิดเห็นของฉันก็ดูดีขึ้น: '(ฉันโพสต์ครั้งแรกเพราะฉันไม่รู้จัก JToken.Parse
Rick Leitch

1
ไม่ใช่ nitpicky เลย - มีความผิดพลาดอยู่แน่นอนและมีมากกว่าหนึ่งวิธีที่จะทำ อย่างไรก็ตาม Json.NET รุ่นของฉันรองรับไวยากรณ์โดยใช้ตัวทำดัชนีJObjectแต่โค้ดที่ฉันแก้ไขสำหรับคำตอบของฉันถูกดึงออกมาจากโค้ดทำให้ใช้โอเวอร์โหลดของSelectTokenวิธีการมากขึ้นดังนั้นฉันจึงสามารถระงับข้อยกเว้นหากโทเค็นไม่ได้ ค้นพบ: JToken JToken.SelectToken(string tokenName, bool errorWhenNoMatch)นั่นคือที่มาของคำฟุ่มเฟื่อย
arcain

18

ถ้าอย่างฉันคุณต้องการจัดการกับวัตถุที่พิมพ์อย่างมาก ** ไปกับ:

MyObj obj =  JsonConvert.DeserializeObject<MyObj>(jsonString);

วิธีนี้คุณจะได้ใช้การตรวจสอบข้อผิดพลาดชนิดของเวลาในการรวบรวมและรวบรวม

คุณสามารถสร้างวัตถุที่ต้องการได้อย่างง่ายดายโดยการคัดลอก JSON ของคุณไปไว้ในหน่วยความจำและวางเป็นวัตถุ JSON (Visual Studio -> แก้ไข -> วางแบบพิเศษ -> วาง JSON เป็นคลาส)

ดูที่นี่หากคุณไม่มีตัวเลือกนั้นใน Visual Studio

คุณจะต้องตรวจสอบให้แน่ใจว่า JSON ของคุณถูกต้อง เพิ่มวัตถุของคุณเองเมื่อเริ่มต้นหากเป็นเพียงอาร์เรย์ของวัตถุ เช่น { "obj": [{}, {}, {}]}

ฉันรู้ว่าไดนามิกทำให้บางครั้งง่ายขึ้น แต่ฉันก็โอเคกับเรื่องนี้


1
ที่ฉันชอบมากเข้าหาการเขียนโปรแกรม ฉันชอบวัตถุที่พิมพ์ได้ดี ขอบคุณสำหรับฉันใช้และแก้ไขรหัสนี้
j.hull

11

รายการแบบไดนามิกที่พิมพ์หลวม - ยกเลิกการจัดทำและอ่านค่า

// First serializing
dynamic collection = new { stud = stud_datatable }; // The stud_datable is the list or data table
string jsonString = JsonConvert.SerializeObject(collection);


// Second Deserializing
dynamic StudList = JsonConvert.DeserializeObject(jsonString);

var stud = StudList.stud;
foreach (var detail in stud)
{
    var Address = detail["stud_address"]; // Access Address data;
}

8

ฉันชอบวิธีนี้:

using Newtonsoft.Json.Linq;
// jsonString is your JSON-formatted string
JObject jsonObj = JObject.Parse(jsonString);
Dictionary<string, object> dictObj = jsonObj.ToObject<Dictionary<string, object>>();

ตอนนี้คุณสามารถเข้าถึงทุกสิ่งที่คุณต้องการโดยใช้dictObjเป็นพจนานุกรม คุณสามารถใช้Dictionary<string, string>หากคุณต้องการรับค่าเป็นสตริง

คุณสามารถใช้วิธีเดียวกันนี้เพื่อส่งเป็นวัตถุ. NET ชนิดใดก็ได้


2
ฉันพบว่าวิธีนี้ดีมากด้วยเหตุผลสองประการ: 1) เมื่อคุณไม่สนใจประเภทข้อมูล (ทุกอย่างเป็นสตริง) และ 2) สะดวกในการทำงานกับพจนานุกรมของค่า
netfed

7

นอกจากนี้หากคุณกำลังมองหาค่าเฉพาะที่ซ้อนอยู่ในเนื้อหา JSON คุณสามารถทำสิ่งต่อไปนี้:

yourJObject.GetValue("jsonObjectName").Value<string>("jsonPropertyName");

และจากที่นั่น

สิ่งนี้จะช่วยได้ถ้าคุณไม่ต้องการแบกค่าใช้จ่ายในการแปลง JSON ทั้งหมดเป็นวัตถุ C #


2

ฉันอยาก Extionclass สำหรับ json:

 public static class JsonExtentions
    {
        public static string SerializeToJson(this object SourceObject) { return Newtonsoft.Json.JsonConvert.SerializeObject(SourceObject); }


        public static T JsonToObject<T>(this string JsonString) { return (T)Newtonsoft.Json.JsonConvert.DeserializeObject<T>(JsonString); }
}

รูปแบบการออกแบบ:

 public class Myobject
    {
        public Myobject(){}
        public string prop1 { get; set; }

        public static Myobject  GetObject(string JsonString){return  JsonExtentions.JsonToObject<Myobject>(JsonString);}
        public  string ToJson(string JsonString){return JsonExtentions.SerializeToJson(this);}
    }

การใช้งาน:

   Myobject dd= Myobject.GetObject(jsonstring);

                 Console.WriteLine(dd.prop1);


1

สายไปงานเลี้ยงค่อนข้างยุติธรรม แต่ฉันเจอปัญหานี้ด้วยตัวเองวันนี้ที่ทำงาน นี่คือวิธีที่ฉันจะแก้ไขปัญหา

ฉันกำลังเข้าถึง API บุคคลที่สามเพื่อดึงรายชื่อหนังสือ วัตถุส่งคืนวัตถุ JSON ขนาดใหญ่ที่มีฟิลด์มากกว่า 20+ รายการซึ่งฉันต้องการเพียง ID เป็นวัตถุสตริงรายการเท่านั้น ฉันใช้ linq บนวัตถุไดนามิกเพื่อดึงข้อมูลเฉพาะที่ฉันต้องการแล้วใส่มันลงในรายการวัตถุสตริงของฉัน

dynamic content = JsonConvert.DeserializeObject(requestContent);
var contentCodes = ((IEnumerable<dynamic>)content).Where(p => p._id != null).Select(p=>p._id).ToList();

List<string> codes = new List<string>();

foreach (var code in contentCodes)
{
    codes.Add(code?.ToString());
}

0

ในที่สุดรับชื่อรัฐจาก JSON

ขอบคุณ!

Imports System
Imports System.Text
Imports System.IO
Imports System.Net
Imports Newtonsoft.Json
Imports Newtonsoft.Json.Linq
Imports System.collections.generic

Public Module Module1
    Public Sub Main()

         Dim url As String = "http://maps.google.com/maps/api/geocode/json&address=attur+salem&sensor=false"
            Dim request As WebRequest = WebRequest.Create(url)
        dim response As WebResponse = DirectCast(request.GetResponse(), HttpWebResponse)
        dim reader As New StreamReader(response.GetResponseStream(), Encoding.UTF8)
          Dim dataString As String = reader.ReadToEnd()

        Dim getResponse As JObject = JObject.Parse(dataString)

        Dim dictObj As Dictionary(Of String, Object) = getResponse.ToObject(Of Dictionary(Of String, Object))()
        'Get State Name
        Console.WriteLine(CStr(dictObj("results")(0)("address_components")(2)("long_name")))
    End Sub
End Module
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.