C# Deserialize JSON to Dynamic Object Using Newtonsoft.Json

By FoxLearn 1/21/2025 4:29:40 AM   290
When you need to deserialize JSON without creating multiple classes, you can either deserialize it to a dictionary or to a dynamic object using Newtonsoft.Json.

Consider this JSON data:

{
    "name": "Alice",
    "preferences": {
        "color": "blue",
        "animal": "dog"
    }
}

To deserialize this JSON into a dynamic object with Newtonsoft.Json, use JsonConvert.DeserializeObject<dynamic> as shown below:

using Newtonsoft.Json;

var person = JsonConvert.DeserializeObject<dynamic>(json);

Console.WriteLine($"{person.name}'s favorite color is {person.preferences.color}");
Console.WriteLine($"{person.name}'s favorite animal is {person.preferences.animal}");

This will output:

Alice's favorite color is blue
Alice's favorite animal is dog

Deserialize JSON to ExpandoObject

In versions of Newtonsoft.Json prior to v4.0.1 (released in 2014), using dynamic would lead to an exception. In these older versions, you should deserialize to an ExpandoObject using the ExpandoObjectConverter.

using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

dynamic config = JsonConvert.DeserializeObject<ExpandoObject>(json, new ExpandoObjectConverter());

Deserialize JSON Array to Dynamic Object

Let’s say you are working with JSON that contains an array of objects, like this:

{
  "version": 2.0,
  "servers": [
    {
      "name": "web",
      "status": "active"
    },
    {
      "name": "db",
      "status": "inactive"
    },
    {
      "name": "cache",
      "status": "active"
    }
  ]
}

To deserialize this into a dynamic object, you can loop over the array like this:

using Newtonsoft.Json;

var config = JsonConvert.DeserializeObject<dynamic>(json);

Console.WriteLine($"Using API version: {config.version}");

foreach (var server in config.servers)
{
    Console.WriteLine($"{server.name} status: {server.status}");
}

Output:

Using API version: 2
web status: active
db status: inactive
cache status: active

Filtering with LINQ

If you want to filter the array using LINQ, you can cast it to IEnumerable<dynamic> first.

For example, to list only the active servers:

using System.Linq;

Console.WriteLine("Active servers:");
foreach (var activeServer in ((IEnumerable<dynamic>)config.servers).Where(s => s.status == "active"))
{
    Console.WriteLine($"{activeServer.name}");
}

Output:

Active servers:
web
cache

System.Text.Json vs. Newtonsoft.Json

The built-in System.Text.Json library doesn’t handle dynamic deserialization as smoothly as Newtonsoft.Json.

For example:

dynamic config = System.Text.Json.JsonSerializer.Deserialize<dynamic>(json);

When deserializing to a dynamic object, System.Text.Json returns a JsonElement instead. While you can work with JsonElement for JSON Document Model tasks, this doesn't give you true dynamic object behavior. If you need dynamic support, Newtonsoft.Json is the better option.

If you got an error:

InvalidCastException: Unable to cast object of type ‘System.Collections.Generic.List`1[System.Object]’ to type ‘System.Dynamic.ExpandoObject’.

For example:

if (response.IsSuccessStatusCode)
{
    var data = await response.Content.ReadAsStringAsync();
    dynamic config = JsonConvert.DeserializeObject<ExpandoObject>(data, new ExpandoObjectConverter());
}

It seems you're deserializing a JSON array.

Instead of using ExpandoObject, use IEnumerable<ExpandoObject> as the type parameter, like this:

if (response.IsSuccessStatusCode)
{
    var data = await response.Content.ReadAsStringAsync();
    dynamic config = JsonConvert.DeserializeObject<IEnumerable<ExpandoObject>>(data, new ExpandoObjectConverter());
}