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);
Answer from JGilmore on Stack Overflowtl: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);
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);
[SOLVED - Just use a Dictionary<string, string>]
Hey, guys. I'm working on an dotNet 8 app and I'm in a position that I have this problematic object structure:
class MyStrangeClass {
...
string Details { get; set; }
...
}
And this Details property will contain a JSON that has this structure:
{
"main_details": "{ \"Some Key\": \"Some Value\", ..... }",
"extra_details": "{ \"Some Key\": \"Some Value\", ...... }"
}
The main_details and extra_details are contants, but their values are another JSONs with keys that are not. There can be any number of any keys but the value will always be a string.
This works right now as the application just send this to the front-end that has no problem working with it in JS. But now, I have to develop a feature that creates a CSV file with all those keys and values from the JSONs inside main_details and extra_details, so I must deserialize them inside the dotNet app. I have no clue how to deserialize this complex dynamic object so it can be consumed in a CSV generation library. I have googled it but answers vary a lot.
Right now the only thing I'm certain is that I will have 2 steps of deserialization.
How useful is C# "dynamic" with System.Text.Json.Nodes.JsonObject?
how to deserialize json into dynamic object in c# and update field
system.text.json with dynamic object names
c# - How do you read a simple value out of some json using System.Text.Json? - Stack Overflow
Videos
Check one of approaches:
public class Data
{
public string @class { get; set; }
public Value value { get; set; }
}
public class Value
{
public string[] groupNames { get; set; }
public string itemType { get; set; }
public string[] tags { get; set; }
public string label { get; set; }
public string category { get; set; }
}
. . .
Dictionary dictionary = JsonSerializer.Deserialize>( json );
where json is your string. See also other parameters of Deserialize.
Sample usage:
string category = dictionary["TreppenhausOG"].value.category;
If required, use "Manage NuGet Packages" window to add a reference to System.Text.Json.
@Bernd Schmal , Viorel-1's solution is good, I also make a code example for it, you could refer to the following code:
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
namespace ConsoleApp1
{
internal class Program
{
static void Main(string[] args)
{
string jsonstr = File.ReadAllText("D:\\1.json");
Root myDeserializedClass = JsonSerializer.Deserialize(jsonstr);
Console.WriteLine(myDeserializedClass.WohnzimmerEG.value.category);
}
}
public class Value
{
public List groupNames { get; set; }
public string itemType { get; set; }
public List tags { get; set; }
public string label { get; set; }
public string category { get; set; }
}
public class WohnzimmerEG
{
public string @class { get; set; }
public Value value { get; set; }
}
public class TreppenhausOG
{
public string @class { get; set; }
public Value value { get; set; }
}
public class Kinozimmer
{
public string @class { get; set; }
public Value value { get; set; }
}
public class Root
{
public WohnzimmerEG WohnzimmerEG { get; set; }
public TreppenhausOG TreppenhausOG { get; set; }
public Kinozimmer Kinozimmer { get; set; }
}
}
You could get the WohnzimmerEG's category like the following:
Console.WriteLine(myDeserializedClass.WohnzimmerEG.value.category);
Result:
If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".
Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.
you can deserialize to a Dictionary:
var dict = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, string>>(json)
Or just deserialize to Object which will yield a JsonElement that you can call GetProperty on.
Support for JsonObject has been added in .NET 6 using System.Text.Json.Nodes.
Example:
const string Json = "{\"MyNumber\":42, \"MyArray\":[10,11]}";
// dynamic
{
dynamic obj = JsonNode.Parse(Json);
int number = (int)obj["MyNumber"];
Debug.Assert(number == 42);
obj["MyString"] = "Hello";
Debug.Assert((string)obj["MyString"] == "Hello");
}
// JsonObject
{
JsonObject obj = JsonNode.Parse(Json).AsObject();
int number = (int)obj["MyNumber"];
Debug.Assert(number == 42);
obj["MyString"] = "Hello";
Debug.Assert((string)obj["MyString"] == "Hello");
}
Sources:
https://github.com/dotnet/runtime/issues/53195
https://github.com/dotnet/runtime/issues/45188
I have a very complex object that is currently in a List<dynamic> object and would like to write this out to json file. I managed to do this with newtonsoft but it has skipped some data and is not in the format i wanted. Someone at work nudged me to use system.text.json however i now noticed an error with invalid arguments which most likely are causing blank output in the nested data lots of empty arrays returned.
All the guides i see use newtonsoft or poco classes and give the dynamic a type. Is there anything I should be looking into to get this working hopefully an option i can pass into the serializer
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;
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;