Deserializzare l'oggetto JSON su .NET usando Newtonsoft (o forse LINQ to JSON?)


318

So che ci sono alcuni post su Newtonsoft, quindi spero che questo non sia esattamente una ripetizione ... Sto cercando di convertire i dati JSON restituiti dall'API di Kazaa in un bell'oggetto di qualche tipo

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

Quella linea JsonConvert è solo la più recente che stavo provando ... Non ci sto capendo e spero di eliminare un po 'di gioco chiedendogli ragazzi. Inizialmente stavo cercando di convertirlo in un dizionario o qualcosa del genere ... e in realtà, ho solo bisogno di afferrare un paio di valori lì, quindi a giudicare dalla documentazione, forse LINQ to JSON di Newtonsoft potrebbe essere una scelta migliore? Pensieri / link?

Ecco un esempio dei dati di ritorno 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
}

Ho fatto ancora qualche lettura e ho scoperto che LINQ to JSON di Newtonsoft è esattamente quello che volevo ... usando WebClient, Stream, StreamReader e Newtonsoft ... Posso colpire Kazaa per i dati JSON, estrarre un URL, scaricare il file e farlo tutto come sette righe di codice! Lo adoro.

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

Questo post ottiene così tanti successi che ho pensato potesse essere utile includere i bit "using" che sono discussi nei commenti.

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
Semplice esempio, grazie. Solo un suggerimento: potresti averlo lasciato fuori per brevità, ma poiché WebClient, Streame StreamReadertutti gli strumenti IDisposable, potresti voler aggiungere alcuni usingblocchi al tuo codice.
Arcain,

ah sì, buona telefonata ... ... lol
J Benjamin,

1
+1 Grazie per aver pubblicato l'esempio Linq. Esattamente quello di cui avevo bisogno.
Mark Wilkins,

La soluzione newtonsoft non deserializza completamente anche JSON? Proprio come fa la soluzione di @ arcain.
AXMIM,

Nota qui il link: LINQ to JSON
yu yang Jian,

Risposte:


259

Se hai solo bisogno di ottenere alcuni elementi dall'oggetto JSON, utilizzerei la classe LINQ to JSON di Json.NET JObject. Per esempio:

JToken token = JObject.Parse(stringFullOfJson);

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

Mi piace questo approccio perché non è necessario deserializzare completamente l'oggetto JSON. Questo è utile con le API che a volte possono sorprenderti con le proprietà degli oggetti mancanti, come Twitter.

Documentazione: serializzazione e deserializzazione di JSON con Json.NET e LINQ a JSON con Json.NET


1
sì, in realtà ho fatto un po 'più di lettura e test ... ho scoperto che questo è anche un bel modo di farlo ... Newtonsoft, biblioteca piuttosto carina, posterò il mio esempio per altri
J Benjamin

1
pubblicato un esempio approssimativo di come lo stavo facendo ... non esattamente lo stesso, vedo che hai suggerito JToken.Parse ... non sono sicuro delle differenze tra i due ma sì, roba buona!
J Benjamin,

1
@Jbenjamin Grazie! Quello era un errore di battitura. JToken è la classe base per JObject ed è solo la mia preferenza personale lavorare con il tipo più astratto. Grazie per averlo richiamato alla mia attenzione.
Arcain,

Scusa, ma dovrebbe essere JToken o JObject? Il codice sopra genera ancora l'errore "Errore durante la lettura di JObject da JsonReader" di tanto in tanto.
TYRONEMICHAEL,

1
@Tyrone Certo, nessun problema. In realtà utilizzo questo codice anche per l'analisi dello stato di Twitter e ho dovuto scrivere parecchi errori nella gestione delle chiamate su Twitter, poiché a volte possono essere imprevedibili. Se non lo stai già facendo, ti consiglio di scaricare la risposta JSON non elaborata da Twitter a un registro prima di tentare di analizzarla. Quindi se fallisce, puoi almeno vedere se hai ricevuto qualcosa di strano sul filo.
Arcain,

272

Puoi usare il dynamictipo C # per semplificare le cose. Questa tecnica semplifica anche il ricopertura in quanto non si basa su stringhe magiche.

JSON

La stringa JSON di seguito è una semplice risposta da una chiamata API HTTP e definisce due proprietà: Ide Name.

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

C #

Utilizzare JsonConvert.DeserializeObject<dynamic>()per deserializzare questa stringa in un tipo dinamico, quindi accedere semplicemente alle sue proprietà nel solito modo.

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

Se si specifica il tipo di resultsvariabile come dynamic, anziché utilizzare la varparola chiave, i valori delle proprietà verranno deserializzati correttamente, ad es. A Idan inte non a JValue(grazie a GFoley83 per il commento in basso).

Nota : il collegamento NuGet per l'assembly Newtonsoft è http://nuget.org/packages/newtonsoft.json .

Pacchetto : puoi anche aggiungere il pacchetto con nuget live installer, con il tuo progetto aperto basta sfogliare il pacchetto e poi basta installarlo, disinstallare, aggiornare , sarà appena aggiunto al tuo progetto in Dependencies / NuGet


Stavo usando lo stesso codice di cui sopra per deserializzare la risposta di twitter con newtonsoft.dll versione 4.5.6 e funzionava bene .. ma dopo averlo aggiornato alla versione 5.0.6 .. ha iniziato a lanciare errori ... qualsiasi idea perché ??
Pranav,

1
Buono per l'oggetto dinamico, quando sappiamo o abbiamo una classe c # in modo che possiamo consumare come una classe C # in sostituzione di dinamico, ad esempio <Massass>.
MSTdev,

2
Usa dynamic results = JsonConvert.DeserializeObject<ExpandoObject>(json);qui FTW. Deserializzerà correttamente Idin un int e non in un JValue. Vedi qui: dotnetfiddle.net/b0WxGJ
GFoley83

@biofractal Come lo farei dynamic results = JsonConvert.DeserializeObject<dynamic>(json); in VB.NET? Dim results As Object = Newtonsoft.Json.JsonConvert.DeserializeObject(Of Object)(json)non funziona.
Flo


41

Con la dynamicparola chiave, diventa davvero facile analizzare qualsiasi oggetto di questo tipo:

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

Volevo sapere come passare in rassegna i risultati e questo ha impiegato troppo tempo per trovare ... grazie !!
batoutofhell,

22

Correggimi se sbaglio, ma credo che l'esempio precedente sia leggermente non sincronizzato con l'ultima versione della libreria Json.NET di James Newton.

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

1
grazie per la tua risposta Rick, ya che sembra simile agli esempi che ho trovato anche nella documentazione più recente.
J Benjamin,

1
Sì, dal momento che Arcain ha corretto l'errore di battitura, il mio commento ora sembra nitido: '(. Ho pubblicato originariamente perché non riconoscevo JToken.Parse.
Rick Leitch,

1
Non è affatto nitido: c'è stato sicuramente un errore e c'è sempre più di un modo per farlo. A proposito, la mia versione di Json.NET supporta la sintassi utilizzando l'indicizzatore attivo JObject, ma il codice che ho modificato per la mia risposta è stato estratto dal codice facendo uso di un sovraccarico del SelectTokenmetodo in modo da poter sopprimere le eccezioni se il token non lo fosse found JToken JToken.SelectToken(string tokenName, bool errorWhenNoMatch):, ecco da dove viene la verbosità.
Arcain,

18

Se, come me, preferisci trattare oggetti fortemente tipizzati ** vai con:

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

In questo modo è possibile utilizzare intellisense e compilare il controllo degli errori del tipo di tempo.

Puoi facilmente creare gli oggetti richiesti copiando il tuo JSON in memoria e incollandolo come oggetti JSON (Visual Studio -> Modifica -> Incolla speciale -> Incolla JSON come classi).

Vedi qui se non hai questa opzione in Visual Studio.

Dovrai anche assicurarti che il tuo JSON sia valido. Aggiungi il tuo oggetto all'inizio se è solo una matrice di oggetti. ovvero { "obj": [{}, {}, {}]}

** So che la dinamica rende le cose più semplici a volte ma sono un po 'vecchio con questo.


1
Molto il mio preferito si è avvicinato alla programmazione. Mi piacciono gli oggetti con caratteri forti. Grazie, per aver usato e modificato questo codice.
j.hull

11

Elenco dinamico liberamente digitato: deserializza e leggi i valori

// 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

Mi piace questo metodo:

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

Ora puoi accedere a tutto ciò che desideri utilizzando dictObjcome dizionario. Puoi anche usare Dictionary<string, string>se preferisci ottenere i valori come stringhe.

È possibile utilizzare questo stesso metodo per trasmettere qualsiasi tipo di oggetto .NET.


2
Trovo questo metodo molto carino per due motivi: 1) quando non ti interessa il tipo di dati (tutto è stringa), e 2) è conveniente lavorare con un dizionario dei valori
netfed

7

Inoltre, se stai solo cercando un valore specifico nidificato all'interno del contenuto JSON, puoi fare qualcosa del genere:

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

E così via da lì.

Ciò potrebbe essere utile se non si desidera sostenere i costi di conversione dell'intero JSON in un oggetto C #.


2

ho desiderato un Extionclass per 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); }
}

Design pattern:

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

Uso:

   Myobject dd= Myobject.GetObject(jsonstring);

                 Console.WriteLine(dd.prop1);


1

Abbastanza tardi per questa festa, ma oggi mi sono imbattuto in questo problema al lavoro. Ecco come ho risolto il problema.

Stavo accedendo a un'API di terze parti per recuperare un elenco di libri. L'oggetto ha restituito un enorme oggetto JSON contenente circa 20+ campi, di cui avevo solo bisogno dell'ID come oggetto stringa elenco. Ho usato linq sull'oggetto dinamico per recuperare il campo specifico di cui avevo bisogno e quindi l'ho inserito nel mio oggetto stringa Elenco.

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

Infine, ottieni il nome dello stato da JSON

Grazie!

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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.