-1

C# System.Text.Json Can't deserialize response from open sky api. My DTO model doesn't fit I have response body like this and i can't desearilize it to c# dto model:

{
    "time": 1677521877,
    "states": [
        [
            "a2e5ec",
            "SKW3744",
            "United States",
            1677521876,
            1677521876,
            -122.31,
            47.3658,
            1447.8,
            false,
            102.38,
            179.42,
            7.48,
            null,
            1280.16,
            null,
            false,
            0
        ]
    ]
}

This is my dto model for this response:

public class RootObjectOfFlightStatus
{
    [JsonPropertyName("time")]
    public long Time { get; set; }

    [JsonPropertyName("states")]
    public List<List<FlightStatusOpenSkyDto>>? States { get; set; }
}

public class FlightStatusOpenSkyDto
{
    [JsonPropertyName("0")]
    public string? Icao24 { get; set; }

    [JsonPropertyName("1")]
    public string? Callsign { get; set; }

    [JsonPropertyName("2")]
    public string? OriginCountry { get; set; }

    [JsonPropertyName("3")]
    public int? TimePosition { get; set; }

    [JsonPropertyName("4")]
    public int? LastContact { get; set; }

    [JsonPropertyName("5")]
    public float? Longitude { get; set; }

    [JsonPropertyName("6")]
    public float? Latitude { get; set; }

    [JsonPropertyName("7")]
    public float? BaroAltitude { get; set; }

    [JsonPropertyName("8")]
    public bool? OnGround { get; set; }

    [JsonPropertyName("9")]
    public float? Velocity { get; set; }

    [JsonPropertyName("10")]
    public float? TrueTrack { get; set; }

    [JsonPropertyName("11")]
    public float? VerticalRate { get; set; }

    [JsonPropertyName("12")]
    public int[]? Sensors { get; set; }

    [JsonPropertyName("13")]
    public float? GeoAltitude { get; set; }

    [JsonPropertyName("14")]
    public string? Squawk { get; set; }

    [JsonPropertyName("15")]
    public bool? Spi { get; set; }

    [JsonPropertyName("16")]
    public int? PositionSource { get; set; }

    [JsonPropertyName("17")]
    public int? Category { get; set; }
}`

`RootObjectOfFlightStatus? flightStatusOpenSkyDto = JsonSerializer.Deserialize<RootObjectOfFlightStatus>(here is respone); 

and I get

flightStatusOpenSkyDto

value always null. I'm short of ideas what is wrong here. Could you please help?

I suggest the trouble is in this line of code.

public List<List<FlightStatusOpenSkyDto>>? States { get; set; } 

I tried here several options but still get the same result:

List<FlightStatusOpenSkyDto[]>? States,
FlightStatusOpenSkyDto[][]? States 
  • `"states"` is a list of a list of objects, not a list of dictionary. So you can't deserialize "a2e5ec" in `Icao24 ` property if the json is not `"Icao24 ": "a2e5ec"`. You have to deserialize into a list of objects, then based on indexes convert it to your object – AoooR Mar 01 '23 at 14:31

2 Answers2

2

Your FlightStatusOpenSkyDto class is expecting there to be JSON in the form of "0": "value", "1": "another value"... which doesn't match. Instead, you are going to have to either write your own custom converter or you could simply use object instead. For example:

public class RootObjectOfFlightStatus
{
    ...
    [JsonPropertyName("states")]
    public List<List<JsonElement>> States { get; set; }
}

Then you can do something like this:

var result = JsonSerializer.Deserialize<RootObjectOfFlightStatus>(Json);

var icao24 = result.States[0][0].GetString();
var timePosition = result.States[0][3].GetInt32();
DavidG
  • 113,891
  • 12
  • 217
  • 223
-1

You can try this code

using System.Text.Json;

var jNode = System.Text.Json.Nodes.JsonNode.Parse(json);

var arr = new JsonArray();
foreach (var jArr in jNode["states"].AsArray())
{
    var statesObj = new  Dictionary< string,JsonNode>();
        for (int i = 0; i < jArr.AsArray().Count; i++)
            statesObj.Add( i.ToString(), jArr[i]);
    arr.Add(statesObj);
}

RootObjectOfFlightStatus rootObjectOfFlightStatus = new RootObjectOfFlightStatus
{
    Time = (long)jNode["time"],
    States = arr.Deserialize <List<FlightStatusOpenSkyDto>>() 
};

and it seems to me that you have to fix your class or a json since the last positions json and class are not sync. Also fix your root class

public class RootObjectOfFlightStatus
{
    public long Time { get; set; }
    public List<FlightStatusOpenSkyDto>? States { get; set; }
}

test

var originCountry = rootObjectOfFlightStatus.States[0].OriginCountry; //"United States"

var icao24 = rootObjectOfFlightStatus.States[0].Icao24; // "a2e5ec"

FlightStatusOpenSkyDto flightStatus = rootObjectOfFlightStatus.States[0];

PropertyInfo[] properties = typeof(FlightStatusOpenSkyDto).GetProperties();
foreach (PropertyInfo prop in properties)
    Console.WriteLine(prop.Name + " : " + prop.GetValue(flightStatus));

Icao24 : a2e5ec
Callsign : SKW3744
OriginCountry : United States
TimePosition : 1677521876
LastContact : 1677521876
Longitude : -122.31
Latitude : 47.3658
BaroAltitude : 1447.8
OnGround : False
Velocity : 102.38
TrueTrack : 179.42
VerticalRate : 7.48
Sensors : 
GeoAltitude : 1280.16
Squawk : 
Spi : False
PositionSource : 0
Category : 
Serge
  • 40,935
  • 4
  • 18
  • 45
  • Why should he use an extern library ? `System.Text.Json` has `JsonElement` instead of `JObject` – AoooR Mar 01 '23 at 14:52
  • @AoooR I think Text.Json is garbage and try not to use it. – Serge Mar 01 '23 at 14:56
  • I think this could have been true a few years ago, but `System.Text.Json` has improved a lot. All the basic features of Newtonsoft are in SystemText (cf https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/migrate-from-newtonsoft?pivots=dotnet-7-0 ) and I think it is always a bad idea to import external libraries if there is a built-in way to do it. Moreover SystemText is more performant (cf https://medium.com/@tobias.streng/net-performance-series-2-newtonsoft-vs-system-text-json-2bf43e037db0 ) – AoooR Mar 01 '23 at 15:06
  • @AoooR MS just "borrowed" some ideas from Newtonsoft. But it will take a lot of time till they copy Newtonsoft completely. Maybe after this i will change my mind. If Newtonsoft had only Text.Json possibilities it would be much faster then Text.Json – Serge Mar 01 '23 at 15:27
  • 1
    I'm sorry, but your hatred of STJ is just nonsense. Also, none of the code above will work, how do you expect this will map the values into the `FlightStatusOpenSkyDto` object? – DavidG Mar 01 '23 at 15:29
  • @DavidG I never post the code that was not tested. And you can see the test results too. – Serge Mar 01 '23 at 17:46
  • @DavidG I just don't want to propagandize Text.Json by posting the solution that uses it. I am afraid that users can think that it is good to use System.Text.Json. It is like c# and Vb.net. I don't think that MS should keep big team to mantain Vb.net. It would be more usefull if they use this team to make c# more robust. The same way here. We dont need another serializer since we have alreaday the good old one. The best is the enemy of the good. – Serge Mar 01 '23 at 17:49
  • FWIW we did need a new JSON serialiser. For all the good stuff that JSON.Net does, it is poor at memory management, it is very slow, and it doesn't have the capability to do anything async. All those combined would have destroyed the performance we see in the current benchmarks for .NET. As for VB.Net, you have clearly never worked in a corporate environment before where that is most used. – DavidG Mar 02 '23 at 09:41
  • @DavidG I am sorry, but I don't think that it is a good library that will finish task 2ns faster, but I will have to spend several days to make a custom converter for almost any trivial json. Nobody will ever notice 2ns. – Serge Mar 02 '23 at 10:30
  • I have used STJ extensively in production and have yet to need to write a custom converter. Also, again you are missing the point of performance. It's not 2ns, it's much, much more. OK if your API is low traffic, then it's not much of a benefit, but at any kind of scale, it becomes important. – DavidG Mar 02 '23 at 11:41