partial & dynamic JSON deserialization in C#

2k views Asked by At

I have a JSON that has the following form:

{
   "type": "oneOfMyTypes",
   "body": {
       //object corresponding to the type, contains some key-value pairs"
   }
}

The structure of the body object depends on the type. So, I want to read the type, check that it is one of my predefined types, switch on the type and parse the body into a different object depending on the type. Body objects can be very different and I do not want to make a "super body" object containing all possible attributes. I also want to use JSON and I do not want to use any binary formats.

Question: How can this be achieved using System.Text.Json or Utf8Json?

So far I have found JsonDocument+JsonElement and Utf8JsonReader. After the type is known, I will know the appropriate class for the body so I would like to use a simple parsing technique for the body, for example using JsonSerializer.Deserialize.

Answered here: Is polymorphic deserialization possible in System.Text.Json?

2

There are 2 answers

2
Heinz Kessler On

Assuming you are using Newtonsoft.Json:

When serializing, use the TypeNameHandling.Auto setting. This instructs the serializer to save the type of an object as well. When deserializing, a 'body' object of this type will be reconstructed.

var json = JsonConvert.SerializeObject(testResults,
    Formatting.Indented,
    new JsonSerializerSettings {
        TypeNameHandling = TypeNameHandling.Auto
    });

See also: https://www.newtonsoft.com/json/help/html/SerializeTypeNameHandling.htm

1
Gusman On

If you can use Json.net (a lot more flexible) then you can use JObject for this purpose:

//First, parse the json as a JObject
var jObj = JObject.Parse(json);

//Now switch the type
switch(jObj["type"].ToString())
{

    case "oneOfMyTypes":

        var oneType = jObj["body"].ToObject<oneOfMyTypes>();
    
        //process it as you need

        break;

    case "otherOfMyTypes":

        var otherType = jObj["body"].ToObject<otherOfMyTypes>();

        //process it...

        break;

    //...

    //unsupported type
    default:

        throw new InvalidDataException("Unrecognized type");

}