C# – Deserialize JSON to dynamic object

If you want to deserialize JSON without having to create a bunch of classes, you can either deserialize to a dictionary or deserialize to a dynamic object with Newtonsoft.Json. Here’s an example. Let’s say you want to deserialize the following JSON:

{
    "name":"Bob",
    "favorites":{
        "number":7,
        "food":"cheese"
    }
}Code language: JSON / JSON with Comments (json)

To deserialize this to a dynamic object with Newtonsoft, use JsonConvert.DeserializeObject<dynamic>:

using Newtonsoft.Json;

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

Console.WriteLine($"{person.name}'s favorite number is {person.favorites.number}")
Console.WriteLine($"{person.name}'s favorite food is {person.favorites.food}");
Code language: C# (cs)

This outputs the following:

Bob's favorite number is 7
Bob's favorite food is cheeseCode language: plaintext (plaintext)

Deserialize to ExpandoObject in older versions of Newtonsoft

Before Newtonsoft v4.0.1 (released in 2014), specifying <dynamic> didn’t work. 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

If you’re using an older version of Newtonsoft (before v4.0.1):

  • Use JsonConvert.DeserializeObject<ExpandoObject>
  • Pass in ExpandoObjectConverter.

Here’s an example:

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

dynamic config = JsonConvert.DeserializeObject<ExpandoObject>(json, new ExpandoObjectConverter());
Code language: C# (cs)

Example – Deserialize JSON array to dynamic object

Here’s another example of deserializing JSON to a dynamic object with Newtonsoft. Let’s say you’re deserializing JSON that contains an array of objects:

{
  "version":1.0,
  "endpoints": [
    {
      "name": "prod",
      "enabled": true
    },
    {
      "name": "dev",
      "enabled": true
    },
    {
      "name": "qa",
      "enabled": false
    }
  ]
}Code language: JSON / JSON with Comments (json)

You can deserialize this to dynamic and loop over the array with a regular foreach:

using Newtonsoft.Json;

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

Console.WriteLine($"Using api verison: {apiConfig.version}");

foreach(var endpoint in apiConfig.endpoints)
{
    Console.WriteLine($"{endpoint.name} enabled? {endpoint.enabled}");
}
Code language: C# (cs)

This outputs the following:

Using api verison: 1
prod enabled? True
dev enabled? True
qa enabled? FalseCode language: plaintext (plaintext)

Cast to IEnumerable<dynamic> to use Linq methods

If you want to use a Linq method on the dynamic object’s array, cast it to IEnumerable<dynamic> first, like this:

Console.WriteLine("Enabled endpoints:");
foreach (var enabledEndpoint in ((IEnumerable<dynamic>)apiConfig.endpoints).Where(t => t.enabled))
{
    Console.WriteLine($"{enabledEndpoint.name}");
}
Code language: C# (cs)

This gets rid of compiler error CS1977 – Cannot use lambda expression as argument to dynamically dispatched… .

System.Text.Json vs Newtonsoft.Json

The built-in System.Text.Json doesn’t work well for deserializing to dynamic objects:

dynamic config = System.Text.Json.JsonSerializer.Deserialize<dynamic>(json);
Code language: C# (cs)

When you try to deserialize to dynamic or ExpandoObject, System.Text.Json deserializes it to JsonElement. This is fine if you want to work with JSON DOM (read: using JsonDocument and using JsonNode). However this defeats the purpose of deserializing to dynamic. For true dynamic support, stick with Newtonsoft.

9 thoughts on “C# – Deserialize JSON to dynamic object”

  1. 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?

    Reply
    • 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"))

      Reply
  2. 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’.

    Reply
    • 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());
      }

      Reply
  3. “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? 😉

    Reply
  4. 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?

    Reply
    • 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 }

      Reply

Leave a Reply to Swat Cancel reply