If you want to deserialize JSON without having to create a bunch of classes, use Newtonsoft.Json like this:
dynamic config = JsonConvert.DeserializeObject<ExpandoObject>(json, new ExpandoObjectConverter());
Code language: C# (cs)
Now you can use this object like any other object.
Table of Contents
Example
Add the Newtonsoft.Json reference

Code
string json = "{\"endpoints\":[{\"name\":\"prod\", \"enabled\":true },{\"name\":\"dev\", \"enabled\":true},{\"name\":\"qa\", \"enabled\":false}]}"; //see JSON section below for pretty printed JSON
dynamic config = JsonConvert.DeserializeObject<ExpandoObject>(json, new ExpandoObjectConverter());
Console.WriteLine($"Deserialized JSON into {config.GetType()}");
foreach (var enabledEndpoint in ((IEnumerable<dynamic>)config.endpoints).Where(t => t.enabled))
{
Console.WriteLine($"{enabledEndpoint.name} is enabled");
}
Code language: C# (cs)
Output:
Code language: plaintext (plaintext)Deserialized JSON into System.Dynamic.ExpandoObject prod is enabled dev is enabled
JSON
{
"endpoints": [
{
"name": "prod",
"enabled": true
},
{
"name": "dev",
"enabled": true
},
{
"name": "qa",
"enabled": false
}
]
}
Code language: JSON / JSON with Comments (json)
Dynamic vs ExpandoObject
If you specify <dynamic> instead of <ExpandoObject> it’ll create a JObject.
In older versions of Newtonsoft, when you tried to access a dynamic property on JObject, you’d get an exception like this:
JObject does not contain a definition for property
This is no longer the case. You can use JObject just like ExpandoObject in new versions of Newtonsoft. However, I wanted to show a code example that will definitely work in whatever version of Newtonsoft you’re using.
Why cast to (IEnumerable<dynamic>)?
If you try to use config.endpoints.Where() like this:
foreach (var enabledEndpoint in config.endpoints.Where(t => t.enabled))
Code language: C# (cs)
You’ll get the following compile error:
Cannot use a lambda expression as an argument to a dynamically dispatched operation without first casting it to a delegate or expression tree type.
This is why we have to cast it to (IEnumerable<dynamic>).
System.Text.Json vs Newtonsoft.Json
I tried to deserialize into a dynamic object using the built-in System.Text.Json, but it doesn’t work well. I tried it using .NET Core 3.1.
Example:
dynamic config = System.Text.Json.JsonSerializer.Deserialize<ExpandoObject>(json);
Code language: C# (cs)
System.Text.Json deserializes this into an ExpandoObject with JsonElement properties. In my example, config.endpoints is a JsonElement. In order to loop over this, I’d have to use config.endpoints.EnumerateArray(). This returns JsonElement objects.
It’s JsonElements all the way down. In other words, this is not a nice clean way to deserialize JSON into a dynamic object.
Perhaps System.Text.Json will be improved later on, but as of right now, Newtonsoft.Json is better.
Go with Newtonsoft.Json.
Amazing ! Like magic !!! Thanks!
Thanks Mak – this is a real life problem for developers… 🙂
How can we handle the situation where the properties are dynamic could be added or deleted based on JSON response
i.e. Name & Enabled
In future if we get Name, Enabled and Owner
… is there a way to dynamically cater this?
You can check if the dynamic object (ExpandoObject) has a property by casting it to an IDictionary<string, object>. Its Keys are the properties.
Using the example code from this article, let’s say I want to check if one of the endpoint objects has a property called “owner”.
I would check that by doing this:
if ((enabledEndpoint as IDictionary<string, object>).ContainsKey("owner"))
if (response.IsSuccessStatusCode)
{
var data = await response.Content.ReadAsStringAsync();
dynamic config = JsonConvert.DeserializeObject<ExpandoObject>(data, new ExpandoObjectConverter());
}
I get following error.
InvalidCastException: Unable to cast object of type ‘System.Collections.Generic.List`1[System.Object]’ to type ‘System.Dynamic.ExpandoObject’.
Looks like you are deserializing a JSON array. Use IEnumerable<ExpandoObject> as the type parameter instead of ExpandoObject, like this:
if (response.IsSuccessStatusCode)
{
var data = await response.Content.ReadAsStringAsync();
dynamic config = JsonConvert.DeserializeObject<IEnumerable<ExpandoObject>>(data, new ExpandoObjectConverter());
}
“In older versions of Newtonsoft, when you tried to access a dynamic property on JObject, you’d get an exception like this [..]”
Could you tell me in which version they fixed it? 😉
Version 4.0.1
Example:-
dynamic config = JsonConvert.DeserializeObject(data, new ExpandoObjectConverter());
Can we try to update some values here in dynamic config object and then convert it back to the json. Would that be possible?
Yes, you can do that. Here’s an example.
//1. Get JSON as dynamic object
string json = "{\"Enabled\":true}";
dynamic config = JsonConvert.DeserializeObject<ExpandoObject>(json, new ExpandoObjectConverter());
//2. Change a value, and serialize back to JSON
config.Enabled = false;
var changedJson = JsonConvert.SerializeObject(config);
Console.WriteLine(changedJson);
This outputs the changed JSON: { "Enabled": false }