Deserializing JSON ke objek .NET menggunakan Newtonsoft (atau LINQ ke JSON mungkin?)

318

Saya tahu ada beberapa posting tentang Newtonsoft jadi mudah-mudahan ini bukan pengulangan ... Saya mencoba mengubah data JSON yang dikembalikan oleh API Kazaa menjadi objek yang bagus.

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

Garis JsonConvert itu adalah yang terbaru yang saya coba ... Saya tidak mengerti dan berharap untuk menghilangkan beberapa gerak kaki dengan bertanya pada kalian. Saya awalnya mencoba mengubahnya menjadi Kamus atau sesuatu ... dan sebenarnya, saya hanya perlu merobek beberapa nilai di sana sehingga menilai dari dokumentasi, mungkin LINQ ke JSON dari Newtonsoft mungkin merupakan pilihan yang lebih baik? Pikiran / Tautan?

Berikut adalah contoh data pengembalian 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
}

Saya melakukan beberapa bacaan lagi dan menemukan LINQ Newtonsoft ke JSON persis seperti yang saya inginkan ... menggunakan WebClient, Stream, StreamReader, dan Newtonsoft ... Saya dapat menekan Kazaa untuk data JSON, mengekstrak URL, mengunduh file, dan melakukannya semuanya seperti tujuh baris kode! Aku menyukainya.

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

Posting ini mendapat begitu banyak hit saya pikir mungkin akan membantu untuk memasukkan bit "using" yang dibahas dalam komentar.

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"]);
}
J Benjamin
sumber
6
Contoh apik, terima kasih. Hanya saran: Anda mungkin membiarkannya singkat, tetapi karena WebClient, Streamdan StreamReadersemua implementasinya IDisposable, Anda mungkin ingin menambahkan beberapa usingblok ke kode Anda.
Arcain
ah ya, panggilan yang bagus ... (ya ini sebenarnya hanya sebuah aplikasi konsol yang saya jalankan sangat cepat untuk penelitian untuk tugas-tugas yang telah saya buat) Sekarang pergi untuk meneliti bagian terakhir dari teka-teki, enkripsi HLS + AES :) ugh ... lol
J Benjamin
1
+1 Terima kasih telah memposting contoh Linq. Apa yang saya butuhkan.
Mark Wilkins
Apakah solusi newtonsoft tidak sepenuhnya membatalkan deserialisasi JSON? Sama seperti solusi @ arcain lakukan.
AXMIM
Perhatikan tautannya di sini: LINQ ke JSON
yu yang Jian

Jawaban:

259

Jika Anda hanya perlu mendapatkan beberapa item dari objek JSON, saya akan menggunakan LINQ Json.NET untuk JObjectkelas JSON . Sebagai contoh:

JToken token = JObject.Parse(stringFullOfJson);

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

Saya suka pendekatan ini karena Anda tidak perlu sepenuhnya deserialize objek JSON. Ini berguna dengan API yang terkadang dapat mengejutkan Anda dengan properti objek yang hilang, seperti Twitter.

Dokumentasi: Melakukan Serialisasi dan Deserialisasi JSON dengan Json.NET dan LINQ ke JSON dengan Json.NET

arcain
sumber
1
ya saya sebenarnya telah melakukan sedikit lebih banyak membaca dan menguji ... menemukan ini menjadi cara yang baik untuk melakukannya juga ... Newtonsoft, perpustakaan yang cukup bagus, saya akan memposting contoh saya untuk orang lain
J Benjamin
1
memposting contoh kasar tentang bagaimana saya melakukannya ... tidak persis sama, saya melihat Anda menyarankan JToken.Parse ... tidak yakin tentang perbedaan antara keduanya namun ya, bagus!
J Benjamin
1
@Jbenjamin Terima kasih! Itu salah ketik. JToken adalah kelas dasar untuk JObject, dan itu hanya preferensi pribadi saya untuk bekerja dengan tipe yang lebih abstrak. Terima kasih telah memanggil itu untuk perhatian saya.
Arcain
Maaf, tetapi haruskah itu JToken, atau JObject? Kode di atas masih melempar kesalahan "Kesalahan membaca JObject dari JsonReader" setiap sekarang dan kemudian.
TYRONEMICHAEL
1
@ Tyone Tentu, tidak masalah. Saya benar-benar menggunakan kode ini untuk penguraian status Twitter juga, dan saya harus menulis sedikit kesalahan dalam menangani panggilan ke Twitter karena kadang-kadang bisa jerawatan. Jika Anda belum melakukannya, saya akan merekomendasikan membuang respons JSON mentah dari Twitter ke log sebelum mencoba menguraikannya. Kemudian jika gagal, Anda setidaknya dapat melihat apakah Anda menerima sesuatu yang funky.
Arcain
272

Anda dapat menggunakan tipe C # dynamicuntuk mempermudah. Teknik ini juga membuat re-factoring lebih sederhana karena tidak bergantung pada string sihir.

JSON

String JSON di bawah ini adalah respons sederhana dari panggilan HTTP API, dan mendefinisikan dua properti: Iddan Name.

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

C #

Gunakan JsonConvert.DeserializeObject<dynamic>()untuk menghilangkan tanda dari string ini menjadi tipe dinamis lalu cukup mengakses propertinya dengan cara yang biasa.

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

Jika Anda menentukan jenis resultsvariabel sebagai dynamic, alih-alih menggunakan varkata kunci, maka nilai properti akan deserialize dengan benar, misalnya Idke intdan bukan JValue(terima kasih kepada GFoley83 untuk komentar di bawah).

Catatan : Tautan NuGet untuk perakitan Newtonsoft adalah http://nuget.org/packages/newtonsoft.json .

Paket : Anda juga dapat menambahkan paket dengan installer langsung nuget, dengan proyek Anda dibuka lakukan browse paket lalu instal saja instal, unistall, perbarui , itu hanya akan ditambahkan ke proyek Anda di bawah Dependensi / NuGet

biofractal
sumber
Saya menggunakan potongan kode yang sama seperti di atas untuk menghilangkan racun respon twitter dengan versi 4.5.6 newtonsoft.dll dan itu berfungsi dengan baik .. tapi setelah memperbaruinya ke versi 5.0.6 .. itu mulai melempar kesalahan ... ada ide kenapa ??
Pranav
1
Baik untuk objek dinamis, ketika kita tahu atau kita memiliki kelas c # sehingga kita dapat mengkonsumsi sebagai kelas C # pada penggantian yang dinamis misalnya <Myclass>.
MSTdev
2
Gunakan di dynamic results = JsonConvert.DeserializeObject<ExpandoObject>(json);sini FTW. Ini akan deserialize dengan benar Idke int dan bukan a JValue. Lihat di sini: dotnetfiddle.net/b0WxGJ
GFoley83
@ biofractal Bagaimana saya melakukan ini dynamic results = JsonConvert.DeserializeObject<dynamic>(json); di VB.NET? Dim results As Object = Newtonsoft.Json.JsonConvert.DeserializeObject(Of Object)(json)tidak bekerja.
Flo
41

Dengan dynamickata kunci, menjadi sangat mudah untuk mem-parsing objek semacam ini:

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;
}
Sushant Srivastava
sumber
Saya ingin tahu cara mengulang hasil dan ini butuh waktu terlalu lama untuk menemukan ... terima kasih !!
batoutofhell
22

Perbaiki saya jika saya salah, tetapi contoh sebelumnya, saya percaya, hanya sedikit tidak sinkron dengan versi terbaru dari pustaka Json.NET James Newton.

var o = JObject.Parse(stringFullOfJson);
var page = (int)o["page"];
var totalPages = (int)o["total_pages"];
Rick Leitch
sumber
1
terima kasih atas tanggapan Anda Rick, ya yang terlihat mirip dengan contoh yang saya temukan di dokumentasi terbaru juga.
J Benjamin
1
Ya, karena arcain memperbaiki kesalahan ketik, komentar saya sekarang hanya tampak nitpicky: '(. Saya awalnya diposting karena saya tidak mengenali JToken.Parse.
Rick Leitch
1
Sama sekali tidak nitpicky - pasti ada kesalahan, dan selalu ada lebih dari satu cara untuk melakukannya. By the way, versi Json.NET saya memang mendukung sintaks menggunakan pengindeks aktif JObject, tetapi kode yang saya modifikasi untuk jawaban saya ditarik dari penggunaan kode kelebihan SelectTokenmetode sehingga saya bisa menekan pengecualian jika token tidak ditemukan JToken JToken.SelectToken(string tokenName, bool errorWhenNoMatch):, jadi dari situlah verbositas itu berasal.
Arcain
18

Jika, seperti saya, Anda lebih suka berurusan dengan objek yang sangat diketik ** pergi dengan:

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

Dengan cara ini Anda bisa menggunakan intellisense dan mengkompilasi pengecekan tipe waktu.

Anda dapat dengan mudah membuat objek yang diperlukan dengan menyalin JSON Anda ke dalam memori dan menempelkannya sebagai objek JSON (Visual Studio -> Edit -> Paste Special -> Tempel JSON sebagai Kelas).

Lihat di sini jika Anda tidak memiliki opsi itu di Visual Studio.

Anda juga perlu memastikan JSON Anda valid. Tambahkan objek Anda sendiri di awal jika hanya berupa array objek. yaitu { "obj": [{}, {}, {}]}

** Saya tahu dinamika kadang-kadang membuat segalanya lebih mudah, tetapi saya agak bodoh dengan ini.

Guy Lowe
sumber
1
Sangat saya lebih suka mendekati pemrograman. Saya suka objek yang diketik kuat. Terima kasih, karena saya menggunakan dan memodifikasi kode ini.
j.hull
11

Daftar Dinamis Longgar Diketik - Deserialize dan baca nilainya

// 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;
}
Arun Prasad ES
sumber
8

Saya suka metode ini:

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

Sekarang Anda dapat mengakses apa pun yang Anda inginkan menggunakan dictObjkamus. Anda juga dapat menggunakan Dictionary<string, string>jika Anda lebih suka mendapatkan nilai sebagai string.

Anda bisa menggunakan metode yang sama ini untuk melakukan cast seperti segala jenis objek .NET.

Blairg23
sumber
2
Saya menemukan metode ini sangat bagus karena dua alasan: 1) ketika Anda tidak peduli tentang tipe data (semuanya adalah string), dan 2) akan lebih mudah untuk bekerja dengan kamus nilai-nilai
netfed
7

Juga, jika Anda hanya mencari nilai tertentu yang bersarang di dalam konten JSON, Anda dapat melakukan sesuatu seperti:

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

Dan seterusnya dari sana.

Ini bisa membantu jika Anda tidak ingin menanggung biaya konversi seluruh JSON menjadi objek C #.

Tony
sumber
2

saya mengidam Extionclass for 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); }
}

Desain-pola:

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

Pemakaian:

   Myobject dd= Myobject.GetObject(jsonstring);

                 Console.WriteLine(dd.prop1);
Sloomy
sumber
1

Agak terlambat ke pesta ini, tetapi saya menemukan sendiri masalah ini hari ini di tempat kerja. Inilah cara saya memecahkan masalah.

Saya sedang mengakses API pihak ke-3 untuk mengambil daftar buku. Objek mengembalikan objek JSON besar yang berisi sekitar 20 bidang, yang saya hanya membutuhkan ID sebagai objek string Daftar. Saya menggunakan linq pada objek dinamis untuk mengambil bidang spesifik yang saya butuhkan dan kemudian memasukkannya ke objek string Daftar saya.

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());
}
todd.pund
sumber
0

Akhirnya Dapatkan Nama Negara Dari JSON

Terima kasih!

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
iApps Creator India
sumber