Laden...

JSON in C# Klasse serialisieren schlägt fehl

Erstellt von Fab4guy vor 6 Jahren Letzter Beitrag vor 6 Jahren 2.774 Views
F
Fab4guy Themenstarter:in
54 Beiträge seit 2016
vor 6 Jahren
JSON in C# Klasse serialisieren schlägt fehl

Ich versuche ich mich gerade an einer App für IOS mit Visual Studio und Xamarin.

Dazu möchte ich Daten von einer Internetschnittstelle abrufen.

Die php-Datei auf dem Webserver erwartet einen bestimmtes Post-Array und liefert bei Erfolg json zurück.

Mit diesem Codeausschnitt spreche ich die php-Datei an und erhalte auch json zurück.


        string url = "https://www.muster.de/app.php";

        HttpWebRequest httpWReq = (HttpWebRequest)WebRequest.Create( url );

        ASCIIEncoding encoding = new ASCIIEncoding();
        string email = txtMail.Text.Trim();
        string password = txtPassword.Text.Trim();

        string postData="appRequest=76/%&nh()2";
        postData += ( "&site=login" );
        postData += ( "&email=" + email );
        postData += ( "&userPasswort=" + password );

        byte[] data = encoding.GetBytes(postData);

        httpWReq.Method = "POST";
        httpWReq.ContentType = "application/x-www-form-urlencoded";
        httpWReq.ContentLength = data.Length;

        using (Stream stream = httpWReq.GetRequestStream())
        {
          stream.Write(data, 0, data.Length);
        }

        HttpWebResponse response = (HttpWebResponse)httpWReq.GetResponse();

        string responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();
        
        Console.WriteLine(responseString);


        Kicker result = JsonConvert.DeserializeObject<Kicker>(responseString);

Das kommt beim responseString raus. (Sieht für mich richtig aus.)

[{"email":"mail@dlrg-kickers.de","firstname":"Max","lastname":"Mustermann","id":"1","position":"Sturm","height":"181","birthday":"2012-12-11","strongFoot":"rechts"}]

Mit using Newtonsoft.Json; für ich gerne den JsonString in ein Objekt der Klasse Kicker parsen.
Das ist die Klasse Kicker

using System;

namespace kickers
{
  public class Kicker
  {

    public String firstname { get; set; }

    public String lastname { get; set; }

    public String email { get; set; }

    public int kickerID { get; set; }

    public String position { get; set; }

    public int height { get; set; }

    public DateTime birthday { get; set; }

    public String strongFoot { get; set; }

  }
}

Allerdings erhalte ich immer diese Fehlermeldung.

Fehlermeldung:
Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'kickers.Kicker' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly.
To fix this error either change the JSON to a JSON object (e.g. {"name":"value"}) or change the deserialized type to an array or a type that implements a collection interface (e.g. ICollection, IList) like List<T> that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array.
Path '', line 1, position 1.

Jemand eine Idee was ich falsche mache? Mein JsonString ist doch richtig aufgebaut???

16.827 Beiträge seit 2008
vor 6 Jahren

In Deinem Json heisst es zum Beispiel "id", in Deinem Modell aber "kickerId".
Du gibst die Größe im Json als String mit, im Modell ist es aber als Integer definiert.

Ansonsten sei gesagt, dass Dein Json ein Array darstellt, Du aber beim Serialisieren keine Liste/Array willst, sondern ein Objekt.
Lass die eckigen Klammern weg, das indiziert nämlich eine Auflistung in Json.

Evtl. - sofern es knallen sollte - brauchst Du bei dem Zeitstempel einen eigenen Converter.
Denn eine DateTime hat eben auch immer einen Time Anteil.
Würde dann wohl in etwa so aussehen:

public class YearOnlyDateTimeConverter : IsoDateTimeConverter
{
    public YearOnlyDateTimeConverter( )
    {
        base.DateTimeFormat = "yyyy-MM-dd";
    }
}
D
985 Beiträge seit 2014
vor 6 Jahren

Beim Datum würde ich kein Problem erwarten, denn das ist nach ISO8601 kodiert und sollte auch vom Konverter als Standard verwendet werden.

2.207 Beiträge seit 2011
vor 6 Jahren

Hallo Fab4guy,

Tools wie http://json2csharp.com/ sind echt nützlich, aber wie Abt schon sagt: du bekommst ein Array und versuchst es in ein Objekt zu parsen. Das kann nicht funktionieren.

Übrigens sagt die Fehlermeldung genau das. 😃

Gruss

Coffeebean

3.003 Beiträge seit 2006
vor 6 Jahren

Für die Zukunft: die C#-Klasse von Hand schreiben ist keine gute Variante.

a) langsam
b) fehlerbehaftet

Nimm die Zeichenkette, die dir geliefert wird, kopier sie, mach im Visual Studio Bearbeiten->Inhalte Einfügen -> JSON als Klassen einfügen.

Ergibt für deinen Anwendungsfall:


public class Rootobject
{
    public Class1[] Property1 { get; set; }
}

public class Class1
{
    public string email { get; set; }
    public string firstname { get; set; }
    public string lastname { get; set; }
    public string id { get; set; }
    public string position { get; set; }
    public string height { get; set; }
    public string birthday { get; set; }
    public string strongFoot { get; set; }
}

Klasse Rootobject wirfst du weg, Class1 refaktorierst du, indem du die Typen nach Wunsch änderst und ggf Hinweise an den Serializer per Attribut "JsonProperty" gibst:


public class Kicker
{
    public string Email { get; set; }
    public string Firstname { get; set; }
    public string Lastname { get; set; }
    [JsonProperty("id")]
    public int KickerId { get; set; }
    public string Position { get; set; }
    public int Height { get; set; }
    public DateTime Birthday { get; set; }
    public string StrongFoot { get; set; }
}

Test schreiben:


[TestClass]
public class KickerTests
{
    [TestMethod]
    public void DeserializeKickerTest()
    {
        string input = @"[{""email"":""mail@dlrg-kickers.de"",""firstname"":""Max"",""lastname"":""Mustermann"",""id"":""1"",""position"":""Sturm"",""height"":""181"",""birthday"":""2012-12-11"",""strongFoot"":""rechts""}]";

        var expectedResult = new Kicker
        {
            Email = "mail@dlrg-kickers.de",
            Firstname = "Max",
            Lastname = "Mustermann",
            KickerId = 1,
            Position = "Sturm",
            Height = 181,
            Birthday = new DateTime(2012, 12, 11),
            StrongFoot = "rechts"
        };

        var actualResultList = JsonConvert.DeserializeObject<Kicker[]>(input);
        Assert.AreEqual(1, actualResultList.Length);

        var actualResult = actualResultList[0];
        Assert.AreEqual(expectedResult.Email, actualResult.Email);
        Assert.AreEqual(expectedResult.Firstname, actualResult.Firstname);
        Assert.AreEqual(expectedResult.Lastname, actualResult.Lastname);
        Assert.AreEqual(expectedResult.KickerId, actualResult.KickerId);
        Assert.AreEqual(expectedResult.Position, actualResult.Position);
        Assert.AreEqual(expectedResult.Height, actualResult.Height);
        Assert.AreEqual(expectedResult.Birthday, actualResult.Birthday);
        Assert.AreEqual(expectedResult.StrongFoot, actualResult.StrongFoot);
    }
}

Aufwand: ~3-5 Minuten pro Klasse maximal. Und bitte, keine App ohne UnitTestprojekt.

LaTino

"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)

16.827 Beiträge seit 2008
vor 6 Jahren

Tools wie
>
sind echt nützlich

das ist auch schon in Visual Studio seit 2013 eingebaut.