Laden...

JsonConvert.DeserializeObject gibt Fehler "Error converting value XX to type ..."

Erstellt von LittleTester vor einem Jahr Letzter Beitrag vor einem Jahr 740 Views
L
LittleTester Themenstarter:in
158 Beiträge seit 2019
vor einem Jahr
JsonConvert.DeserializeObject gibt Fehler "Error converting value XX to type ..."

Ich habe folgendes JSON auf meiner Webseite. Der Quelltext gibt das ebenfalls exakt so wieder.:


{"id":15,"hardwareComputerSerial":"1A2B3C4"}

Wenn ich nun folgenden Code schreibe, dann bekomme ich auch ein anständiges JSON zurück:


string requestUrl = "https://api.meineseite.tld/api.php";

HttpClient httpClient = new HttpClient();

var hardwareComputerSerial = "1A2B3C4";
var urlParameter = requestUrl + "?hardwareComputerSerial=" + hardwareComputerSerial;

HttpResponseMessage responseMessage = httpClient.GetAsync(urlParameter).Result;
string response = responseMessage.Content.ReadAsStringAsync().Result;

In "respnse" steht dann folgendes:

{"id":15,"hardwareComputerSerial":"1A2B3C4"}

Sieht also gut aus.

Nun will ich das ganze deserialisieren.

Dazu habe ich zwei neue Klassen erstellt:


class Test
{
    public int id;
}

class InventoryResponse
{
    public Test id;
}

und dann den Code um eine Zeile erweitert:


InventoryResponse inventoryAPI = JsonConvert.DeserializeObject<InventoryResponse>(response);

Wenn ich das nun ausführe bekomme ich folgenden Fehler zurück:

Newtonsoft.Json.JsonSerializationException: 'Error converting value 15 to type 'SysteminventoryV2.Api+Test'. Path 'id', line 1, position 8.'

Inner Exception
ArgumentException: Could not cast or convert from System.Int64 to SysteminventoryV2.Api+Test.

This exception was originally thrown at this call stack:
[External Code]

In "response" eine Zeile drüber also, bei


string response = responseMessage.Content.ReadAsStringAsync().Result;

steht plötzlich der Wert "null", also "response | null"

Ich habe das Ganze auch mit


class Test
{
    public string hardwareComputerSerial;
}

class InventoryResponse
{
    public Test hardwareComputerSerial;
}

probiert. Passiert genau das Gleiche, nur dass dann der "Exception

Newtonsoft.Json.JsonSerializationException: 'Error converting value "1A2B3C4" to type 'SysteminventoryV2.Api+Test'. Path 'hardwareComputerSerial', line 1, position 43.'

ArgumentException: Could not cast or convert from System.String to SysteminventoryV2.Api+Test.

This exception was originally thrown at this call stack:
[External Code] steht.

Könnt ihr mir bitte sagen, was ich falsch mache und warum eine Zeile weiter unten plötzlich Einfluss auf eine Variable hat, die weiter oben ohne die Zeile weiter unten bereits den richtigen Wert hat, mit der Zeile dann aber nicht mehr?

IDE: Visual Studio 2022
Sofern nicht anders genannt basieren meine Projekte auf C# und .net 6

16.842 Beiträge seit 2008
vor einem Jahr

Punkt 1: Verwende System.Text.Json
Punkt 2: Du musst mit Eigenschaften arbeiten, nicht mit Feldern.
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/properties

L
LittleTester Themenstarter:in
158 Beiträge seit 2019
vor einem Jahr

Was ist an System.Text.Json besser? Irgendwie wird immer auf das Json von Newtonsoft verwiesen. Da finden sich im Zweifel dann für mich als Anfänger sicher auch mehr Hilfe, weil es wohl jeder kennt und verwendet. Hat ja auch knapp 2,89B downloads bei Nu-Get, was wohl im deutschen 2,89 Millliarden? sind.

Ich habe das trotzdem mal probiert und wohl auch die Lösung gefunden, die mit Newtonsoft funktioniert.
Ich habe die Klasse "InventoryResponse" etwas umgeschrieben und die Klasse "Test" gelöscht. (Ist das richtig?)


class InventoryResponse
{
    public int id;
}

Damit klappt das nun. (Diese "Test"-Klasse kam mir eh komisch vor, habe mich aber natürlich an das Lernbeispiel aus einem Videokurs orientiert.)

Ich habe dann


InventoryResponse inventoryAPI =  JsonConvert.DeserializeObject<InventoryResponse>(response);

auskommentiert und von learn.microsoft.com das Beispiel für "System.Text.Json" versucht umzusetzen. Klappt soweit auch, aber die id ist jetzt "0" (als Zahl, nicht "null")


InventoryResponse? inventoryAPI =  JsonSerializer.Deserialize<InventoryResponse>(response);

Was mache ich falsch?

IDE: Visual Studio 2022
Sofern nicht anders genannt basieren meine Projekte auf C# und .net 6

2.080 Beiträge seit 2012
vor einem Jahr

Irgendwie wird immer auf das Json von Newtonsoft verwiesen.

Weil es das schon sehr lange gibt und sehr lange quasi konkurrenzlos war.
Aber es war eben nur konkurrenzlos, mittlerweile hat Microsoft ihr System.Text.Json draußen.

Da finden sich im Zweifel dann für mich als Anfänger sicher auch mehr Hilfe

System.Text.Json ist in .NET integriert und von Microsoft gibt's genug Doku dazu.
Außerdem wird es viel genutzt, jedes ASP.NET Core Projekt nutzt es unter der Haube.

Ich habe die Klasse "InventoryResponse" etwas umgeschrieben und die Klasse "Test" gelöscht. (Ist das richtig?)

Dass die Test-Klasse raus ist, ist richtig - entweder Du hast den Kurs falsch verstanden, oder der Kurs ist Mist.
Aber Du verwendest immer noch keine Properties (wie Abt geschrieben hat) - deshalb ist die ID auch immer 0.

NuGet Packages im Code auslesen
lock Alternative für async/await

Beim CleanCode zählen nicht die Regeln, sondern dass wir uns mit diesen Regeln befassen, selbst wenn wir sie nicht befolgen - hoffentlich nach reiflichen Überlegungen.

T
2.224 Beiträge seit 2008
vor einem Jahr

Hier auch noch der Link zur Doku von Microsoft zu dem Thema.
Damit kannst du dich einlesen und auch mit dem Beispielen rumtesten.
Dann dürfte die Lösung auch recht schnell zu finden sein.

How to serialize and deserialize (marshal and unmarshal) JSON in .NET

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.842 Beiträge seit 2008
vor einem Jahr

Was ist an System.Text.Json besser?

Wenn Du so eine Frage hast, dann schau doch erstmal in die Docs 🙂 Newtonsoft.Json ist quasi fast Legacy. Wird noch weiter entwickelt aber ist nicht mehr erste Wahl für das pauschale Handhaben von Json, sondern eben für Use Cases.
Migrate from Newtonsoft.Json to System.Text.Json - .NET

System.Text.Json ist "quasi der Nachfolger" von Newtonsoft.Json. Der Macher hinter Newtonsoft.Json - James Newton-King - ist schon lange bei Microsoft (für .NET).
Es gibt nur noch vereinzelte Gründe, dass Netwonsoft.Json verwendet werden sollte - geht prinzipiell aber trotzdem.

T
111 Beiträge seit 2005
vor einem Jahr

Hallo

Meiner Meinung nach geht die Diskussion über NewtonSoft bzw. System.Text.Json am Thema vorbei.

Deine Json sieht doch so aus:

{"id":15,"hardwareComputerSerial":"1A2B3C4"}

d.h. die entsprechende Klasse zum Deseralisieren müsste dann so aussehen:


public class InventoryResponse
{
    public int id {get; set;}
    public string hardwareComputerSerial {get; set;}
}

Damit sollte es (egal welches Paket Du verwendest) funktionieren. Die Klasse kannst Du auch über Visual Studio erstellen lassen, indem Du den Json-String über "Edit/Paste Special/Paste Json as class" in eine vorhandene Datei einfügst.

mfG Thomas

T
2.224 Beiträge seit 2008
vor einem Jahr

@thomas.at
Warum geht das am Thema vorbei?
System.Text.Json ist die Zukunft, NewtonSoft.Json wird früher oder später auf dem Abstellgleis landen.
Da ist es schon ratsam gerade Neueinsteiger bei dem Thema gleich in die richtige Richtung zu schicken.
Und das haben wir auch getan. 😉

Ebenfalls kannst du über die Einstellungen auch die Schreibweise bei Serialisieren ändern.
Die Properties können auch direkt Id und HardwareComputerSerial heißen, dann ist man auch mit Code Guidelins z.B. von C# konform.

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.842 Beiträge seit 2008
vor einem Jahr

Absolut legitim zu sagen, wenn eine Abhängigkeit - in Unkenntnis - verwendet wird, die nicht mehr in der Form zu empfehlen ist, wie es mal war.
Das .NET Team stellt alle Abhängigkeiten um; und das schon seit vielen Jahren. Absolut sinnvoll hierzu kompatibel zu sein.

Wie die Klasse aussehen muss, dass Properties statt Feldern verwendet werden muss, war ja an der Stelle bereits beantwortet.

L
LittleTester Themenstarter:in
158 Beiträge seit 2019
vor einem Jahr

Also erstmal Danke an ALLE.

Danke für den Hinweis auf die neue Implementierung von Json. Leider ist es auch so, dass man bei einer Google-Suche, auch über Google News nichts dazu findet, dass Newtonsoft Json praktisch Out of Date ist. Ich werde also natürlich die neue Variante nutzen.

Danke auch an thomas.at mit dem Klartext-Hinweis auf "{get; set;}". Da habe ich echt noch Probleme. NewtonSoft war da wohl etwas toleranter was sowas anging.

IDE: Visual Studio 2022
Sofern nicht anders genannt basieren meine Projekte auf C# und .net 6

T
2.224 Beiträge seit 2008
vor einem Jahr

Der Sinn und Zweck der Umstellung bei neuen Projekten ist einfach, dass System.Text.Json direkt Teil von .NET ab Core 3.0 ist.
Dadurch entfällt an sich der Grund auf NewtonSoft.Json zu setzen.
Damit würde es sich auch nicht lohnen eine eigene Json Lib weiter zu entwickeln.

Gerade Json ist seit Jahren ein Format ist, was extrem weit verbreitet ist, da macht ein Support direkt in .NET schon Sinn.
NewtonSoft.Json wird noch einige Zeit bleiben aber spätestens mit dem Ende vom .NET Framework wird man auf lange Sicht keine Updates mehr erwarten können.
Es ist also nur eine Frage der Zeit bis es soweit ist.
Es macht also schon Sinn direkt auf System.Text.Json zusetzen.

Selbst in Bestandsprojekten macht es Sinn um z.B. bei einer Migration direkt auf die Kern Klassen aufzubauen.
Spart also auch nochmal unnötigen Aufwand beim umstellen.

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.842 Beiträge seit 2008
vor einem Jahr

Leider ist es auch so, dass man bei einer Google-Suche, auch über Google News nichts dazu findet, dass Newtonsoft Json praktisch Out of Date ist. The future of JSON in .NET Core 3.0 Etwas über vier Jahre alt.
Simpler Hauptgrund für die meisten für den Wechsel auf System.Text.Json: Kompatibilität.

NewtonSoft war da wohl etwas toleranter was sowas anging.

Es gibt in .NET gewisse Regeln, die zu beachten sind. Dazu gehört halt, dass Felder eigentlich nicht public sein sollten. Felder haben gewisse Use Cases.
Fields - C# Programming Guide
Viele Mechanismen von .NET basieren auf solchen Regeln.

Davon abgesehen ist Newtonsoft.Json etwas kulanter was ungültiges Json betrifft.
Das ist ein Use Case, in der eher Newtonsoft.Json verwendet werden sollte als System.Text.Json.