C
C#6mo ago
Pannekoekje

JSON deserialization (proper way?)

Hi, I'm writing a client that consumes some JSON from a websocket. The socket can give multiple types of messages over it, what would be the most efficient (fastest) way to deserialize the JSON objects to classes? All the type of messages are known beforehand. The way I'm doing it now is:
var jsonObject = JsonDocument.Parse(inputJson);
IReponseObject returnObject = null;

if (jsonObject.RootElement.TryGetProperty("error", out JsonElement error))
{
throw new Exception($"Issue found in response: \"{error.ToString()}\"");
}

if (jsonObject.RootElement.TryGetProperty("event", out JsonElement jsonEvent))
{
switch (jsonEvent.ToString())
{
case "authenticate":
returnObject = JsonSerializer.Deserialize<AuthenticatedResponse>(jsonObject);
break;
default:
break;
}
}

if (jsonObject.RootElement.TryGetProperty("action", out JsonElement jsonAction))
{
switch (jsonAction.ToString())
{
case "getTime":
responseContent = jsonObject.RootElement.GetProperty("response");
IReponseObject = JsonSerializer.Deserialize<TimeResponse>(responseContent);

break;
case "getPressure":
responseContent = jsonObject.RootElement.GetProperty("response");
IReponseObject = new PressureResponse() { Pressures = new List<Pressure>() };
if (responseContent.ValueKind == JsonValueKind.Object)
{
var pressure = JsonSerializer.Deserialize<PressureResponse>(responseContent);
(IReponseObject as PressureResponse).Pressure.Add(Pressure);
}
else
{
var pressure = JsonSerializer.Deserialize<List<PressureResponse>>(responseContent);
(IReponseObject as PressureResponses).Pressures.AddRange(Pressure);
}
break;
}
var jsonObject = JsonDocument.Parse(inputJson);
IReponseObject returnObject = null;

if (jsonObject.RootElement.TryGetProperty("error", out JsonElement error))
{
throw new Exception($"Issue found in response: \"{error.ToString()}\"");
}

if (jsonObject.RootElement.TryGetProperty("event", out JsonElement jsonEvent))
{
switch (jsonEvent.ToString())
{
case "authenticate":
returnObject = JsonSerializer.Deserialize<AuthenticatedResponse>(jsonObject);
break;
default:
break;
}
}

if (jsonObject.RootElement.TryGetProperty("action", out JsonElement jsonAction))
{
switch (jsonAction.ToString())
{
case "getTime":
responseContent = jsonObject.RootElement.GetProperty("response");
IReponseObject = JsonSerializer.Deserialize<TimeResponse>(responseContent);

break;
case "getPressure":
responseContent = jsonObject.RootElement.GetProperty("response");
IReponseObject = new PressureResponse() { Pressures = new List<Pressure>() };
if (responseContent.ValueKind == JsonValueKind.Object)
{
var pressure = JsonSerializer.Deserialize<PressureResponse>(responseContent);
(IReponseObject as PressureResponse).Pressure.Add(Pressure);
}
else
{
var pressure = JsonSerializer.Deserialize<List<PressureResponse>>(responseContent);
(IReponseObject as PressureResponses).Pressures.AddRange(Pressure);
}
break;
}
12 Replies
Angius
Angius6mo ago
How to serialize properties of derived classes with System.Text.Jso...
Learn how to serialize polymorphic objects while serializing to and deserializing from JSON in .NET.
Pannekoekje
Pannekoekje6mo ago
I'm trying that
Pannekoekje
Pannekoekje6mo ago
C# Online Compiler | .NET Fiddle
Test your C# code online with .NET Fiddle code editor.
Pannekoekje
Pannekoekje6mo ago
But it isn't working as I expected, am I doing something wrong?
Angius
Angius6mo ago
Define "not working as expected"
Pannekoekje
Pannekoekje6mo ago
See the fiddle, I'd expect the given JSON to be deserialized as an "More"
Pannekoekje
Pannekoekje6mo ago
How to serialize properties of derived classes with System.Text.Jso...
Learn how to serialize polymorphic objects while serializing to and deserializing from JSON in .NET.
Pannekoekje
Pannekoekje6mo ago
Or does it not work for JSON that hasn't been serialized by the serializer?
Angius
Angius6mo ago
IIRC you need some type discriminator in your JSON
Pannekoekje
Pannekoekje6mo ago
What do you mean?
Angius
Angius6mo ago
Example from the docs
// JSON property named `$discriminator` will be the discriminator
[JsonPolymorphic(TypeDiscriminatorPropertyName = "$discriminator")]
// It will be deserialized to `ThreeDimensionalPoint` if `$discriminator` has value `"3d"`
[JsonDerivedType(typeof(ThreeDimensionalPoint), typeDiscriminator: "3d")]
public class BasePoint
{
public int X { get; set; }
public int Y { get; set; }
}

public sealed class ThreeDimensionalPoint : BasePoint
{
public int Z { get; set; }
}
// JSON property named `$discriminator` will be the discriminator
[JsonPolymorphic(TypeDiscriminatorPropertyName = "$discriminator")]
// It will be deserialized to `ThreeDimensionalPoint` if `$discriminator` has value `"3d"`
[JsonDerivedType(typeof(ThreeDimensionalPoint), typeDiscriminator: "3d")]
public class BasePoint
{
public int X { get; set; }
public int Y { get; set; }
}

public sealed class ThreeDimensionalPoint : BasePoint
{
public int Z { get; set; }
}
Pannekoekje
Pannekoekje6mo ago
But that needs to be in the source JSON? As their example doesn't include it Ah, it does it seems.. Well I'll try to get this to work. Thx