Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deserializing JSON to a class containing a dynamic property with System.Text.Json

The objective is to deserialize a JSON response to a wrapper response class containing a dynamic part, using the new System.Text.Json library from NET Core 3.

That is

{
    "fixedProperty": "Hello",
    "dynamicProperty": { 
        "attributeOne": "One",
        "attributeTwo": "Two",
    }
}

to

public class MyResponseClass
{
    public string FixedProperty { get; set; }
    public dynamic DynamicProperty { get; set; }  
}

// Where the dynamic property is one of the classes.
// (MyDataClassOne in the particular JSON example above)
public class MyDataClassOne
{
    public string AttributeOne { get; set; }
    public string AttributeTwo { get; set; }  
}

public class MyDataClassTwo
{
    public string AttributeThree { get; set; }
    public string AttributeFour { get; set; }  
}

...

The type of the dynamic property in the response is always known in advance (depends on the request), and is one of, say, three different classes.

Could not figure out a clean way to do so, except for not having one wrapper class with a dynamic property but multiple distinct response classes for each of the cases (which obviously works fine but is not the desired solution).

EDIT: The solution was to use a generic.

like image 506
Factotum Avatar asked Jan 28 '20 17:01

Factotum


2 Answers

How about something like this?

var myResponseClass = new MyResponseClass();

dynamic myClass = JsonSerializer.Deserialize<ExpandoObject>("{\"fixedProperty\":\"Hello\",\"dynamicProperty\": {\"attributeOne\":\"One\",\"attributeTwo\":\"Two\"}}");
dynamic myProperty = JsonSerializer.Deserialize<ExpandoObject>(myClass.dynamicProperty.ToString());

myResponseClass.FixedProperty = myClass.fixedProperty.ToString();
myResponseClass.DynamicProperty = myProperty;
like image 54
David Specht Avatar answered Oct 25 '22 21:10

David Specht


Since the type of the dynamic property in the response is always known in advance (depends on the request), you can use a generic root object:

public class MyResponseClass<T> 
{ 
    public string FixedProperty { get; set; } 
    public T DynamicProperty { get; set; } 
}

And then declare T to be whatever known concrete class is required, e.g.

var root = JsonSerializer.Deserialize<MyResponseClass<MyDataClassOne>>(responseString);
var fixedProperty = root.fixedProperty;
var attributeOne = root.DynamicProperty?.AttributeOne;
like image 21
dbc Avatar answered Oct 25 '22 23:10

dbc