C# – Deserialize JSON to dynamic object

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());

Now you can use this object like any other object.

Example

Add the Newtonsoft.Json reference

Newtonsoft.JSON nuget package

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"); }

Output:

JSON

{ "endpoints": [ { "name": "prod", "enabled": true }, { "name": "dev", "enabled": true }, { "name": "qa", "enabled": false } ] }

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))

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);

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.

Leave a Comment