Deserialisieren von JSON zu .NET-Objekten mit Newtonsoft (oder LINQ zu JSON vielleicht?)


318

Ich weiß, dass es ein paar Posts über Newtonsoft gibt, also ist dies hoffentlich keine Wiederholung ... Ich versuche, JSON-Daten, die von Kazaas API zurückgegeben werden, in ein nettes Objekt umzuwandeln

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

Diese JsonConvert-Linie ist nur die letzte, die ich versucht habe ... Ich verstehe sie nicht ganz und hatte gehofft, durch die Frage von euch Fußarbeit zu vermeiden. Ich habe ursprünglich versucht, es in ein Wörterbuch oder so etwas zu konvertieren ... und eigentlich muss ich nur ein paar Werte darin festhalten, so dass nach der Dokumentation Newtonsofts LINQ to JSON vielleicht die bessere Wahl ist? Gedanken / Links?

Hier ist ein Beispiel für die JSON-Rückgabedaten:

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

Ich habe noch etwas gelesen und festgestellt, dass Newtonsofts LINQ to JSON genau das ist, was ich wollte ... mit WebClient, Stream, StreamReader und Newtonsoft ... Ich kann Kazaa für JSON-Daten aufrufen, eine URL extrahieren, die Datei herunterladen und es tun Alles in sieben Codezeilen! Ich liebe es.

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

Dieser Beitrag erhält so viele Treffer, dass ich dachte, es könnte hilfreich sein, die "using" -Bits aufzunehmen, die in den Kommentaren besprochen werden.

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
Schickes Beispiel, danke. Nur ein Vorschlag: Sie Kürze wegen dieses aufgehört haben, aber da WebClient, Streamund StreamReaderalle implementieren IDisposable, könnte man einige hinzufügen möchten usingBlöcke zu Ihrem Code.
Arcain

ah ja, guter Anruf ... (ya das war eigentlich nur eine Konsolen-App, die ich sehr schnell ausgeführt habe, um nach den anstehenden Aufgaben zu suchen) Nun geht es weiter, um das letzte Puzzleteil zu untersuchen, die HLS + AES-Verschlüsselung :) ugh ... lol
J Benjamin

1
+1 Danke, dass du das Linq-Beispiel gepostet hast. Genau das, was ich brauchte.
Mark Wilkins

Deserialisiert die newtonsoft-Lösung den JSON nicht vollständig? Genau wie bei @ arcains Lösung.
AXMIM

Beachten Sie den Link hier: LINQ zu JSON
yu yang Jian

Antworten:


258

Wenn Sie nur ein paar Elemente aus dem JSON-Objekt abrufen müssen, würde ich die LINQ to JSON- JObjectKlasse von Json.NET verwenden . Zum Beispiel:

JToken token = JObject.Parse(stringFullOfJson);

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

Ich mag diesen Ansatz, weil Sie das JSON-Objekt nicht vollständig deserialisieren müssen. Dies ist praktisch bei APIs, die Sie manchmal mit fehlenden Objekteigenschaften wie Twitter überraschen können.

Dokumentation: Serialisieren und Deserialisieren von JSON mit Json.NET und LINQ zu JSON mit Json.NET


1
ya Ich habe tatsächlich ein bisschen mehr gelesen und getestet ... fand das auch eine gute Möglichkeit ... Newtonsoft, ziemlich nette Bibliothek, ich werde mein Beispiel für andere veröffentlichen
J Benjamin

1
Ich habe ein grobes Beispiel dafür gepostet, wie ich es gemacht habe ... nicht ganz dasselbe, ich sehe, Sie haben JToken vorgeschlagen.Parse ... Ich bin mir der Unterschiede zwischen den beiden noch nicht sicher, aber ya, gutes Zeug!
J Benjamin

1
@Jbenjamin Danke! Das war ein Tippfehler. JToken ist die Basisklasse für JObject, und es ist nur meine persönliche Präferenz, mit dem abstrakteren Typ zu arbeiten. Vielen Dank, dass Sie mich darauf aufmerksam gemacht haben.
Arcain

Entschuldigung, aber sollte es JToken oder JObject sein? Der obige Code löst immer noch ab und zu den Fehler "Fehler beim Lesen von JObject von JsonReader" aus.
TYRONEMICHAEL

1
@ Tyrone Klar, kein Problem. Ich verwende diesen Code tatsächlich auch für das Parsen des Twitter-Status, und ich musste einige Fehlerbehandlungen für die Anrufe bei Twitter schreiben, da diese manchmal fleckig sein können. Wenn Sie dies noch nicht tun, würde ich empfehlen, die unformatierte JSON-Antwort von Twitter in ein Protokoll zu kopieren, bevor Sie versuchen, sie zu analysieren. Wenn es dann fehlschlägt, können Sie zumindest sehen, ob Sie etwas Funky über den Draht erhalten haben.
Arcain

272

Sie können den C # dynamic-Typ verwenden, um die Arbeit zu vereinfachen. Diese Technik vereinfacht auch das Re-Factoring, da es nicht auf magischen Strings beruht.

JSON

Die folgende JSON-Zeichenfolge ist eine einfache Antwort von einem HTTP-API-Aufruf und definiert zwei Eigenschaften: Idund Name.

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

C #

Verwenden Sie JsonConvert.DeserializeObject<dynamic>()diese Option, um diese Zeichenfolge in einen dynamischen Typ zu deserialisieren und dann einfach auf die übliche Weise auf ihre Eigenschaften zuzugreifen.

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

Wenn Sie den Typ der resultsVariablen als angeben dynamic, anstatt das varSchlüsselwort zu verwenden, werden die Eigenschaftswerte korrekt deserialisiert, z. B. Idzu a intund nicht zu a JValue(danke an GFoley83 für den Kommentar unten).

Hinweis : Der NuGet-Link für die Newtonsoft-Assembly lautet http://nuget.org/packages/newtonsoft.json .

Paket : Sie können das Paket auch mit dem Nuget Live-Installationsprogramm hinzufügen. Wenn Ihr Projekt geöffnet ist, durchsuchen Sie einfach das Paket und installieren Sie es einfach. Installieren, deinstallieren, aktualisieren . Es wird einfach unter Abhängigkeiten / NuGet zu Ihrem Projekt hinzugefügt


Ich habe den gleichen Code wie oben verwendet, um die Twitter-Antwort mit newtonsoft.dll Version 4.5.6 zu deserialisieren, und es hat gut funktioniert. Aber nach dem Update auf Version 5.0.6 hat es angefangen, Fehler zu werfen ... jede Idee Warum ??
Pranav

1
Gut für dynamische Objekte, wenn wir die C # -Klasse kennen oder haben, damit wir sie beim Ersetzen der Dynamik als C # -Klasse verwenden können, z. B. <Myclass>.
MSTdev

2
Verwenden Sie dynamic results = JsonConvert.DeserializeObject<ExpandoObject>(json);hier FTW. Es wird korrekt Idzu einem int und nicht zu einem deserialisiert JValue. Siehe hier: dotnetfiddle.net/b0WxGJ
GFoley83

@biofractal Wie würde ich das dynamic results = JsonConvert.DeserializeObject<dynamic>(json); in VB.NET machen? Dim results As Object = Newtonsoft.Json.JsonConvert.DeserializeObject(Of Object)(json)funktioniert nicht.
Flo


41

Mit dem dynamicSchlüsselwort wird es wirklich einfach, jedes Objekt dieser Art zu analysieren:

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

Ich wollte wissen, wie man die Ergebnisse durchläuft, und das hat viel zu lange gedauert, um es zu finden ... danke !!
Batoutofhell

22

Korrigieren Sie mich, wenn ich mich irre, aber das vorherige Beispiel ist meiner Meinung nach nur geringfügig nicht mit der neuesten Version der Json.NET-Bibliothek von James Newton synchron.

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

1
Vielen Dank für Ihre Antwort Rick, ya, das sieht ähnlich aus wie die Beispiele, die ich auch in der neuesten Dokumentation gefunden habe.
J Benjamin

1
Ja, da Arcain den Tippfehler behoben hat, sieht mein Kommentar jetzt nur noch pingelig aus: '(. Ich habe ursprünglich gepostet, weil ich JToken.Parse nicht erkannt habe.
Rick Leitch

1
Nicht nitpicky überhaupt - es definitiv war ein Fehler, und es gibt immer mehr als ein Weg , es zu tun. Übrigens unterstützt meine Version von Json.NET die Syntax unter Verwendung des Indexers JObject, aber der Code, den ich für meine Antwort geändert habe, wurde aus dem Code abgerufen , der eine Überladung der SelectTokenMethode verwendet, sodass ich Ausnahmen unterdrücken konnte, wenn das Token nicht vorhanden war gefunden : JToken JToken.SelectToken(string tokenName, bool errorWhenNoMatch), daher kam die Ausführlichkeit.
Arcain

18

Wenn Sie sich wie ich lieber mit stark typisierten Objekten beschäftigen **, gehen Sie zu:

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

Auf diese Weise können Sie die Fehlerprüfung von Intellisense und Compile Time Type verwenden.

Sie können die erforderlichen Objekte einfach erstellen, indem Sie Ihren JSON in den Speicher kopieren und als JSON-Objekte einfügen (Visual Studio -> Bearbeiten -> Spezial einfügen -> JSON als Klassen einfügen).

Sehen Sie hier, wenn Sie diese Option in Visual Studio nicht haben.

Sie müssen auch sicherstellen, dass Ihr JSON gültig ist. Fügen Sie zu Beginn Ihr eigenes Objekt hinzu, wenn es sich nur um ein Array von Objekten handelt. dh { "obj": [{}, {}, {}]}

** Ich weiß, dass Dynamik manchmal die Dinge einfacher macht, aber ich bin ein bisschen altmodisch.


1
Sehr mein bevorzugter Ansatz zur Programmierung. Ich mag stark getippte Objekte. Vielen Dank, dass ich diesen Code verwendet und geändert habe.
Rumpf

11

Locker typisierte dynamische Liste - Deserialisieren und lesen Sie die Werte

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

Ich mag diese Methode:

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

Sie können jetzt mit dem dictObjWörterbuch auf alles zugreifen, was Sie möchten . Sie können auch verwenden, Dictionary<string, string>wenn Sie die Werte lieber als Zeichenfolgen abrufen möchten.

Sie können dieselbe Methode verwenden, um jede Art von .NET-Objekt umzuwandeln.


2
Ich finde diese Methode aus zwei Gründen sehr schön: 1) wenn Sie sich nicht für den Datentyp interessieren (alles ist Zeichenfolge), und 2) es ist bequem, mit einem Wörterbuch der Werte zu arbeiten
netfed

7

Wenn Sie nur nach einem bestimmten Wert suchen, der im JSON-Inhalt verschachtelt ist, können Sie Folgendes tun:

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

Und so weiter von dort.

Dies kann hilfreich sein, wenn Sie die Kosten für die Konvertierung des gesamten JSON in ein C # -Objekt nicht tragen möchten.


2

Ich habe eine Extionclass für JSON erstellt:

 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-Muster:

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

Verwendungszweck:

   Myobject dd= Myobject.GetObject(jsonstring);

                 Console.WriteLine(dd.prop1);


1

Ziemlich spät zu dieser Party, aber ich bin heute bei der Arbeit selbst auf dieses Problem gestoßen. Hier ist, wie ich das Problem gelöst habe.

Ich habe auf eine Drittanbieter-API zugegriffen, um eine Liste von Büchern abzurufen. Das Objekt gab ein massives JSON-Objekt mit mehr als 20 Feldern zurück, von denen ich nur die ID als List-String-Objekt benötigte. Ich habe linq für das dynamische Objekt verwendet, um das benötigte Feld abzurufen, und es dann in mein List-String-Objekt eingefügt.

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

Holen Sie sich schließlich den Statusnamen von JSON

Vielen Dank!

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
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.