16

I am using System.Text.Json package to use the serialization and deserialization.

I can deserialize a json string into an object when the type is explicitly specified like below.

var data = JsonSerializer.Deserialize<PersonType>(jsonString);

But the dynamic type does not work. Is it possible to deserialize without having to specify the type? Thank you!

var data = JsonSerializer.Deserialize<dynamic>(jsonString);
Jyina
  • 2,530
  • 9
  • 42
  • 80
  • Does this answer your question? [Deserialize JSON into C# dynamic object?](https://stackoverflow.com/questions/3142495/deserialize-json-into-c-sharp-dynamic-object) – Vulpex Mar 31 '22 at 15:32
  • 2
    @Vulpex OP is specifically asking about System.Text.Json. Although using another deserialiser would work, I don't think it's relevant to this question. – phuzi Mar 31 '22 at 15:35
  • 3
    https://github.com/dotnet/runtime/issues/31175 – stuartd Mar 31 '22 at 15:37
  • @phuzi unless System.Text.Json is an abslute necessity to use, it offers a couple of nice and easy ways to accomplish that task. Granted it does not slove the issue with using System.Text.Json, I'm not even sure it can do that (to be fair I rarely use it anyway) – Vulpex Mar 31 '22 at 15:37
  • Seems like you could use `JsonNode` in .Net 6 - https://github.com/dotnet/runtime/issues/31175#issuecomment-937646022 – phuzi Mar 31 '22 at 15:42
  • It's not built in to System.Text.Json, but you could use a custom converter. `ObjectAsPrimitiveConverter` from [this answer](https://stackoverflow.com/a/65974452/3744182) to [C# - Deserializing nested json to nested Dictionary](https://stackoverflow.com/q/65972825/3744182) has an option to deserialize JSON objects to .NET ExpandoObjects. Demo here: https://dotnetfiddle.net/1Y6hI6. Is that what you want? – dbc Mar 31 '22 at 16:11
  • You can refer to this answer with an example of parsing `JSON` with dynamic using `System.Text.Json`: https://stackoverflow.com/a/71491706/1807452 – Rahul Sharma Mar 31 '22 at 16:13
  • @RahulSharma your answer in that question refers to Newtonsoft.JSON, doesn’t it? The issue I linked to above says it is not - and not planned to be - possible to deserialise to dynamic with System.Text.Json because it would mean adding a dependency - see https://github.com/dotnet/runtime/issues/31175#issuecomment-937646022 – stuartd Mar 31 '22 at 17:48
  • @stuartd Please go through the answer. The second portion of the answer uses the MS library for parsing JSON – Rahul Sharma Mar 31 '22 at 17:49
  • I did read the answer - it uses `JsonDocument.Parse` which is a good way of doing it IMO - but I’m not seeing an actual `dynamic` object? – stuartd Mar 31 '22 at 17:52

2 Answers2

22

tl:dr JsonNode is the recommended way but dynamic typing with deserializing to ExpandoObject works and I am not sure why.

It is not possible to deserialize to dynamic in the way you want to. JsonSerializer.Deserialize<T>() casts the result of parsing to T. Casting something to dynamic is similar to casting to object

Type dynamic behaves like type object in most circumstances. In particular, any non-null expression can be converted to the dynamic type. The dynamic type differs from object in that operations that contain expressions of type dynamic are not resolved or type checked by the compiler. The compiler packages together information about the operation, and that information is later used to evaluate the operation at run time

docs.

The following code snippet shows this happening with your example.

var jsonString = "{\"foo\": \"bar\"}";
dynamic data = JsonSerializer.Deserialize<dynamic>(jsonString);
Console.WriteLine(data.GetType());

Outputs: System.Text.Json.JsonElement

The recommended approach is to use the new JsonNode which has easy methods for getting values. It works like this:

JsonNode data2 = JsonSerializer.Deserialize<JsonNode>(jsonString);
Console.WriteLine(data2["foo"].GetValue<string>());

And finally trying out this worked for me and gives you want you want but I am struggling to find documentation on why it works because according to this issue it should not be supported but this works for me. My System.Text.Json package is version 4.7.2

dynamic data = JsonSerializer.Deserialize<ExpandoObject>(jsonString);
Console.WriteLine(data.GetType());
Console.WriteLine(data.foo);
JGilmore
  • 266
  • 3
  • 5
  • 11
    Regarding your observation that `JsonSerializer.Deserialize()` mysteriously works, my guess is that System.Text.Json is able to deserialize to ExpandoObject because it has a parameterless constructor and implements `IDictionary`. However, the **values** are getting deserialized as `JsonElement` rather than as .NET primitives or nested expandos, which you can see if you do `Console.WriteLine($"data.foo={data.foo}, data.foo.GetType()={data.foo.GetType()}");`. Demo here: https://dotnetfiddle.net/nxKBB2. So there's no deserialization to a dynamic hierarchy built in. – dbc Mar 31 '22 at 17:26
  • 2
    @dbc do you know what is the solution to convert it to primitive types recursively ? – Srivathsa Harish Venkataramana Dec 21 '22 at 09:18
  • 3
    @SrivathsaHarishVenkataramana - It's not built in to System.Text.Json, but you could use a custom converter. `ObjectAsPrimitiveConverter` from [this answer](https://stackoverflow.com/a/65974452/3744182) to [C# - Deserializing nested json to nested Dictionary](https://stackoverflow.com/q/65972825/3744182) has an option to recursively deserialize JSON objects to .NET ExpandoObjects and primitives. Demo here: https://dotnetfiddle.net/1Y6hI6 – dbc Dec 21 '22 at 09:48
  • @dbc you're a System.Text.json hero! Thanks – Srivathsa Harish Venkataramana Dec 21 '22 at 11:45
3

I have tried using System.Text.Json in a dynamic way and it just does not work in an easy and meaningful way it seems. So while not a direct answer to your question, but I was "forced" to use the good old Newtonsoft.Json that just works:

dynamic result = JObject.Parse(message);
Ilya Chernomordik
  • 27,817
  • 27
  • 121
  • 207