Laden...

Wie kann ich ein JSON in ein Objekt deserialisieren?

Erstellt von J4m3s90 vor 3 Jahren Letzter Beitrag vor 3 Jahren 644 Views
J
J4m3s90 Themenstarter:in
17 Beiträge seit 2021
vor 3 Jahren
Wie kann ich ein JSON in ein Objekt deserialisieren?

Hallo zusammen,

ich hoffe, ich bin im richtigen Bereich gelandet.
Ich möchte eine JSON string als auswertbares Objekt in meinem Programm einfügen.

Das Problem ist, dass ich nur den ersten Wert bekomme und nicht die restlichen.


{"type":"FeatureCollection","metadata":
{"generated":1612941799000,
"url":"https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/significant_month.geojson","title":"USGS Significant Earthquakes, Past Month","status":200,"api":"1.10.3","count":13},"features":[{"type":"Feature","properties":
{"mag":6.3,"place":"Bismarck Sea","time":1612676752249,"updated":1612850520358,"tz":null,
"url":"https://earthquake.usgs.gov/earthquakes/eventpage/us6000dfad",
"detail":"https://earthquake.usgs.gov/earthquakes/feed/v1.0/detail/us6000dfad.geojson",
"felt":1,"cdi":7.2,"mmi":4.081,"alert":"green","status":"reviewed","tsunami":0,
"sig":611,"net":"us",
"code":"6000dfad","ids":",us6000dfad,","sources":",us,",
"types":",dyfi,ground-failure,losspager,moment-tensor,origin,phase-data,shakemap,","nst":null,"dmin":1.801,"rms":0.87,"gap":43,"magType":"mww",
"type":"earthquake","title":"M 6.3 - Bismarck Sea"},"geometry":{"type":"Point","coordinates":[146.0591,-3.2929,10]},"id":"us6000dfad"},

{"type":"Feature","properties":{"mag":6,"place":"0 km WSW of Bansalan, Philippines","time":1612671776507,"updated":1612845102813,"tz":null,
"url":"https://earthquake.usgs.gov/earthquakes/eventpage/us6000df9r",
"detail":"https://earthquake.usgs.gov/earthquakes/feed/v1.0/detail/us6000df9r.geojson",
"felt":53,"cdi":8.7,"mmi":6.938,"alert":"green","status":"reviewed","tsunami":0,"sig":600,
"net":"us","code":"6000df9r","ids":",us6000df9r,","sources":",us,","types":",dyfi,ground-failure,losspager,moment-tensor,origin,phase-data,shakemap,","nst":null,"dmin":0.467,"rms":1.38,"gap":37,"magType":"mww","type":"earthquake",
"title":"M 6.0 - 0 km WSW of Bansalan, Philippines"},"geometry":{"type":"Point","coordinates":[125.2056,6.7833,15.55]},"id":"us6000df9r"},

{"type":"Feature","properties":{"mag":6.7,"place":"West Chile Rise",
"time":1612329824293,"updated":1612416513747,"tz":null,
"url":"https://earthquake.usgs.gov/earthquakes/eventpage/us6000de34",
"detail":"https://earthquake.usgs.gov/earthquakes/feed/v1.0/detail/us6000de34.geojson",
"felt":3,"cdi":3.8,"mmi":0,"alert":"green","status":"reviewed","tsunami":1,"sig":692,"net":"us","code":"6000de34",
"ids":",us6000de34,pt21034001,at00qnxtnq,","sources":",us,pt,at,","types":",dyfi,impact-link,losspager,moment-tensor,origin,phase-data,shakemap,","nst":null,"dmin":13.422,"rms":1.07,"gap":70,"magType":"mww","type":"earthquake",
"title":"M 6.7 - West Chile Rise"},"geometry":{"type":"Point","coordinates":[-97.6645,-36.1899,10]},"id":"us6000de34"},


Ansich möchte ich auf die properties zugreifen, habe aber aktuell schon Probleme überhaupt eine Liste zu bekommen mit allen type Werten.

Hatte am Anfang noch public string type zu stehen aber habe nur einen Wert bekommen, bei einer List gibt es eine Exception.
Hat jemand eine Idee wo der Fehler liegt?

Grüße Rob


  class Earthquake
    {
        public int mag { get; set; }
        public string place { get; set; }
        public long time { get; set; }

        public List<string> type { get; set; }
    }
    class Program
    {
        static void Main(string[] args)
        {
            WebRequest request = WebRequest.Create("http://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/significant_month.geojson");
            WebResponse response = request.GetResponse();

            using (Stream dataStream = response.GetResponseStream())
            {
                // Open the stream using a StreamReader for easy access.
                StreamReader reader = new StreamReader(dataStream);
                // Read the content.
                string responseFromServer = reader.ReadToEnd();
                // Display the content.
                Console.WriteLine(responseFromServer);

                var options = new JsonSerializerOptions(JsonSerializerDefaults.Web);
                var earthquake = JsonSerializer.Deserialize<Earthquake>(responseFromServer, options);
                
                }
        }
    }

T
2.219 Beiträge seit 2008
vor 3 Jahren

Der Aufbau deiner Klasse passt nicht zu dem Json.

Du brauchst hier eine viel umfangreiche Klasse, da type nur ein String ist.
Im Browser wird das ganze i.d.R. auch strukturierter dargestellt, was die Umsetzung der Klasse auch vereinfacht.
Schau dir doch mal die Url in Chrome/Firefox an.

Je nach Ebene musst du schauen welche Struktur du dort hast und muss diese als Property der jeweiligen übergeordneten Struktur umsetzen.

Ich habe auf den ersten Blick folgende Struktur ermittelt.
Diese ist aber unfertig, Properties enthält noch eine Menge Felder die du noch hinzufügen müsstest.
Wenn die Struktur einigermaßen passt, solltest du schon einen guten Teil der Informationen auslesen können.
Kannst dich etwas damit austoben und lernen wie du die Strukturen umsetzen musst.


public class Earthquake
{
    public string Type { get; set; }
	
	public Metadata Metadata { get; set; }
	
	public List<Feature> Features { get; set; }
}

public class Metadata
{
    public long Generated { get; set; }
	
	public string Url { get; set; }
	
	public string Title { get; set; }
	
	public int status { get; set; }
	
	public string Api { get; set; }
	
	public int Count { get; set; }
}

public class Feature
{
	public string Type { get; set; }
	
	public Properties Properties { get; set; }
	
	public string Id { get; set; }
	
	public Geometry Geometry { get; set; }
}

public class Properties
{
	public int Mag { get; set; }
}

public class Geometry
{
	public string Type { get; set; }
	
	public List<double> Coordinates { get; set; }
}

Nachtrag:
Du solltest die Abfrage der Url nicht mehr mit WebRequest/WebResponse machen.
Nutzt dazu am besten den HttpClient, da WebRequest nicht mehr weiterentwickelt wird und auch in der Doku darauf verwiesen wird.

Hinweis bei WebRequest

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

16.806 Beiträge seit 2008
vor 3 Jahren

ich hoffe, ich bin im richtigen Bereich gelandet.

... wars leider nicht (genauso wenig die richtigen Code Tags 🙂 - aber ich habs korrigiert.

Nimm einfach Refit für sowas; kannste in ner Handvoll Zeilen Quellcode umsetzen und bekommst 90% geschenkt.
reactiveui/refit

J
J4m3s90 Themenstarter:in
17 Beiträge seit 2021
vor 3 Jahren

Danke dir, probiere ich nachher gleich aus.
Mir ging es auch nicht darum, dass jemand mir alles erstellt.
Brauchte nur einen Denkanstoß!

Danke dir!

J
J4m3s90 Themenstarter:in
17 Beiträge seit 2021
vor 3 Jahren

Was mache ich denn bei Name mit einen Leerzeichen dazwischen?


    "Meta Data": {
        "1. Information": "Heavy",
        "2. Symbol": "Paul",
        "3. Last Hit": "2021-02-09 19:55:00",
        "4. Output Size": "Compact",

    },

Danke auch für den Hinweis auf das Git Projekt , allerdings wollte ich es lieber mit den Standard Funktionsumfang erstellen.
Schaue es mir aber trotzdem an.

T
2.219 Beiträge seit 2008
vor 3 Jahren

Wo kommt den der Fall her?
In dem Beispiel liegt gibt es keine Leerzeichen in den Metadata.
Bitte mal den Link posten wo das vorkommt, dann muss man auch erstmal prüfen ob dort nicht eine andere Struktur nötig ist.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

J
J4m3s90 Themenstarter:in
17 Beiträge seit 2021
vor 3 Jahren
309 Beiträge seit 2020
vor 3 Jahren

Siehe: https://json2csharp.com/


// Root myDeserializedClass = JsonConvert.DeserializeObject<Root>(myJsonResponse); 
    public class MetaData    {
        [JsonProperty("1.Information")]
        public string _1Information { get; set; } 
        [JsonProperty("2.Symbol")]
        public string _2Symbol { get; set; } 
        [JsonProperty("3.LastHit")]
        public string _3LastHit { get; set; } 
        [JsonProperty("4.OutputSize")]
        public string _4OutputSize { get; set; } 
    }

    public class Root    {
        public MetaData MetaData { get; set; } 
    }



J
J4m3s90 Themenstarter:in
17 Beiträge seit 2021
vor 3 Jahren

Hey JimStark,

das hatte ich auch schon gesehen, allerdings sagt mir hier mein VS, dass JsonProperty keine Attributklasse ist.

16.806 Beiträge seit 2008
vor 3 Jahren

Bitte beachten, dass json2sharp leider oft keine korrekten Resultate erzeugt; vor allem nicht mit .NET Core und System.Text.Json!
Auch hier fehlt das Leerzeichen in der JsonProperty.

JsonProperty keine Attributklasse ist.

Dann fehlt Dir einfach das Using.
Siehe Basics zu Json: Serialisieren und Deserialisieren von JSON mit C# – .NET

J
J4m3s90 Themenstarter:in
17 Beiträge seit 2021
vor 3 Jahren

Habe ich beide, aber der Fehler steht trotzdem noch an.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Http;
using System.IO;
using System.Text.Json;
using System.Text.Json.Serialization;

using System.Text.RegularExpressions;

namespace Test
{
    class Earthquake
    {
        public int mag { get; set; }
        public string place { get; set; }
        public long time { get; set; }

        public List<string> type { get; set; }
    }
    public class Joa
    {
        
   
        public string BindingType { get; set; }
        [JsonProperty("Meta Data")]
        public Metadata Metadata { get; set; }
    }
    public class Metadata
    {
        public string Information { get; set; }
        public string Symbol { get; set; }
        public DateTime LastRefreshed { get; set; }
        public string Interval { get; set; }
        
    }
    class Program
    {
        static readonly HttpClient client = new HttpClient();
        static void Main(string[] args)
        {
            Task task = Main();
            while (true)
            {

            }
        }
        static async Task Main()
        {
            HttpResponseMessage response = await client.GetAsync("https://www.alphavantage.co/query?function=TIME_SERIES_DAILY_ADJUSTED&symbol=MSFT&apikey=demo");
            response.EnsureSuccessStatusCode();

            string responseBody = await client.GetStringAsync("https://www.alphavantage.co/query?function=TIME_SERIES_DAILY_ADJUSTED&symbol=MSFT&apikey=demo");
            Console.WriteLine(responseBody);
            var options = new JsonSerializerOptions(JsonSerializerDefaults.Web);
            var joa = JsonSerializer.Deserialize<Joa>(responseBody, options);


        }
    }
}

T
2.219 Beiträge seit 2008
vor 3 Jahren

Die while(true) Schleife kannst du wieder rauswerfen.
Ebenfalls kannst du auch Main als async von .NET aufrufen lassen.
Dann sparst du dir die Überladungen.

T-Virus

Developer, Developer, Developer, Developer....

99 little bugs in the code, 99 little bugs. Take one down, patch it around, 117 little bugs in the code.

16.806 Beiträge seit 2008
vor 3 Jahren

Habe ich beide, aber der Fehler steht trotzdem noch an.

Ich hab Dir einen Link gegeben, damit Du ihn durchliest.
Wenn Du Hilfe nicht durchlesen magst, dann musst es einfach sagen.

Bei System.Text.Json heisst es JsonPropertyName, nicht JsonProperty.
How to migrate from Newtonsoft.Json to System.Text.Json

J
J4m3s90 Themenstarter:in
17 Beiträge seit 2021
vor 3 Jahren

Tatsächlich hatte ich den Teil aus einem Beispiel noch im Programm.
Danke, hatte die Seite heute früh schon 2 mal gelesen!

16.806 Beiträge seit 2008
vor 3 Jahren

Offensichtlich nicht, denn Du verwendest immer noch JsonProperty statt JsonPropertyName.
Willst Du das beibehalten, dann kannst eben nicht mit System.Text.Json arbeiten sondern brauchst Newtonsoft.Json.

Verwendest Du dann entsprechend das using richtig, dann gibt es auch den Fehler nicht.
Ansonsten hast Du das einzigen Fall im gesamten Universum, bei dem es anders wäre.

J
J4m3s90 Themenstarter:in
17 Beiträge seit 2021
vor 3 Jahren

Halt Moment 😉

Ich glaube da ist jetzt was nicht richtig rüber gekommen. Habe den Text heute früh gelesen, aber den Sinn hinter dem zweiten Using nicht verstanden. Deshalb habe ich den eben kurz rein genommen.

Nach deinem Hinweis habe ich natürlich auf JsonPropertyName gewechsel und es ging, deshalb auch das Danke!
War nur ein Missverständis!

Eine Frage wäre noch offen. Wie lese ich jetzt die Time Series ein. Diese ändert sich ja täglich. Bevor ich es mit einer Auswertung vom String mache, gibt es hier auch eine Möglichkeit über JsonSerializer?

Grüße und vielen Dank für die bisherige Unterstützung !!

16.806 Beiträge seit 2008
vor 3 Jahren

Bitte nimm Dir doch für solche Fragen wenigstens 10 Sekunden Zeit um zu schauen, ob das nicht schon in der Dokumentation steht 🙂
Das ist echt nicht zuviel verlangt. Siehe auch [Hinweis] Wie poste ich richtig?

Newtonsoft hat von Haus aus einen UnixDateTimeConverter.

https://www.newtonsoft.com/json/help/html/DatesInJSON.htm
Und damit Du den richtigen Typ für Zeiten in .NET verwendest: [FAQ] DateTime vs. DateTimeOffset und der Umgang mit Zeiten in .NET

J
J4m3s90 Themenstarter:in
17 Beiträge seit 2021
vor 3 Jahren

Habe ich gesehen.
Habe aber auch oben schon geschrieben, dass ich gerne auf fremde Bibliotheken verzichten möchte.
Okay, dann mache ich die Auswertung einfach im String.

Danke euch für die Hilfe!

16.806 Beiträge seit 2008
vor 3 Jahren

Du weisst schon, dass Newtonsoft eine externe Bibliothek ist, die Du da verwendest (auch wenn der Macher mittlerweile bei Microsoft ist)?
Du weißt schon, dass das Ökosystem von .NET darauf basiert, dass externe Pakete verwendet werden?

Wenn Du das nicht willst, dann bist mit .NET (und eigentlich mit jeder anderen Technologie) falsch.
Gibt quasi kein modernes Ökosystem, das nicht mit externen Paketen gedacht ist.

Aber gut; manchmal muss man im Leben Fehler machen, um draus zu lernen.
Viel Erfolg! 🙂

J
J4m3s90 Themenstarter:in
17 Beiträge seit 2021
vor 3 Jahren

Deshalb verwende ich auch kein Newtonsoft!

16.806 Beiträge seit 2008
vor 3 Jahren

Na, wenn Du jetzt doch schon System.Text.Json verwendest, dann hast ja vorher schon den Link bekommen, wie man Strings in DateTimeOffset serialisiert.
Dann hat sich ja die Frage schon erledigt. Perfekt. Top! 👍

Ist dann auch mein letzter Beitrag hier

J
J4m3s90 Themenstarter:in
17 Beiträge seit 2021
vor 3 Jahren

Aktuell mache ich das noch ja.
Wenn es nachher wirklich nicht so will, dann werde ich vermutlich doch mal Newtonsoft probieren.

Im Beispiel unten fehlt mir noch bei TimeSeries die ganzen anderen Werte.
Ansonsten bin ich schon sehr zufrieden 🙂, wollte hier nur wissen ob es dort direkt eine Variante gibt die ich benutzen kann, oder ob ich mir was zusammen bauen muss.


  public class Joa
    {

        [JsonPropertyName("Meta Data")]
        public Metadata Metadata { get; set; }
        [JsonPropertyName("Time Series (Daily)")]

        public TimeSeries TimeSeries { get; set; }
    }

    public class TimeSeries
    {
        //hier jetzt die einzelnen Daten als Member anlegen?
        [JsonPropertyName("2021-02-09")] // Da sich der Wert jeden Tag verändert, bzw. Tage es nachher in Minuten ablaufen soll und nicht Tagen, brauche ich hier noch eine alternative!
               Datum Datum { get; set; }
    }

    public class Datum
    {
        [JsonPropertyName("1. open")]
        public double Open { get; set; }
        [JsonPropertyName("2. high")]
        public double High { get; set; }
        [JsonPropertyName("3. low")]
        public double Low { get; set; }

    }
    public class Metadata
    {
        [JsonPropertyName("1. Information")]
        public string Information { get; set; }
        [JsonPropertyName("2. Symbol")]
        public string Symbol { get; set; }
        [JsonPropertyName("3. Last Refreshed")]
        public DateTime LastRefreshed { get; set; }   
    }

309 Beiträge seit 2020
vor 3 Jahren

Von welchen JSON Daten sprichst du jetzt?
Das ist nicht mehr das von oben? Zeig mal ein Beispiel

J
J4m3s90 Themenstarter:in
17 Beiträge seit 2021
vor 3 Jahren
D
152 Beiträge seit 2013
vor 3 Jahren

Die "Time Series (Daily)" sehen für mich wie ein Dictionary aus, wo der Key der Tag ist.


public class TimeSeries: Dictionary<string, Datum>
{
}

ggf. geht auch folgendes


public class TimeSeries: Dictionary<DateTime, Datum>
{
}

Musst mal sehen.

J
J4m3s90 Themenstarter:in
17 Beiträge seit 2021
vor 3 Jahren

Sehr gute Idee,
damit sind alle meine Fragen beantwortet.
Es hat alles so funktioniert wie es soll und ich kann auf alle Daten zugreifen 🙂.

Habe es mit :


 public Dictionary<string,Datum> TimeSeries { get; set; }

gemacht!

Vielen Dank an alle und sorry wenn ich zu wenig in der Dokumentation geschaut habe.
(*Sorry Abt 😉 *)

16.806 Beiträge seit 2008
vor 3 Jahren

Brauchst Dich bei mir nicht entschuldigen.
Du tust Dir selbst keinen Gefallen / schadest Dir selbst, wenn Du nicht in die Doku schaust und so schneller (und sicher) an Deine Antwort kommst. ¯_(ツ)_/¯