JSON and C# dynamic: Why It's Still a Pain (and How to Fix It)
\n\nHave you ever looked at a JSON response from an API and thought: "Lord, why do you have to be so complicated?" Especially when the data structure changes as often as the weather in St. Petersburg. A classic example is a response from an external service where fields can be strings, arrays, or even null. Or when you need to quickly parse JSON, but creating a separate class for it feels like using a microscope to solder a microchip.
That's exactly when the magic of dynamic in C# comes in handy. The question "Deserialize JSON into C# dynamic object?" on Stack Overflow has gathered thousands of views — and for good reason. In 2025, when microservices and dynamic APIs have become the norm, the ability to work with JSON quickly and flexibly is a developer's superpower.
In this article, we'll break down the best practices for deserializing JSON into a dynamic object in C#. No boring theory, just code, examples, and real-life hacks. Let's go!
\n\nWhy dynamic? Why not just JObject?
\n\nGood question. C# has JObject (from Newtonsoft.Json) and JsonDocument (from System.Text.Json). They can also parse JSON on the fly. But dynamic gives you one important thing — syntactic sugar.
Compare:
\n\n// Using JObject\nvar json = JObject.Parse(rawJson);\nvar name = (string)json["user"]["name"];\n\n// Using dynamic\ndynamic obj = JsonConvert.DeserializeObject<dynamic>(rawJson);\nvar name = obj.user.name;\n\n\nThe second option reads like regular code, not like "get the key, cast the type, check for null." This is especially convenient when the JSON is deeply nested.
\n\nMethod 1: The Classic — Newtonsoft.Json (Json.NET)
\n\nYes, it's 2025, but Newtonsoft.Json is still alive and well. Many legacy projects, and even some modern ones, still use it. Why? Flexibility, extensibility, and a million settings.
\n\nBasic Example
\n\nusing Newtonsoft.Json;\n\nstring json = @"\n{\n 'name': 'Alexey',\n 'age': 30,\n 'skills': ['C#', 'Python', 'SQL'],\n 'address': {\n 'city': 'Moscow',\n 'zip': 101000\n }\n}";\n\ndynamic obj = JsonConvert.DeserializeObject<dynamic>(json);\n\nConsole.WriteLine(obj.name); // Alexey\nConsole.WriteLine(obj.age); // 30\nConsole.WriteLine(obj.skills[0]); // C#\nConsole.WriteLine(obj.address.city); // Moscow\n\n\nSimple and elegant. But there's a catch: when working with dynamic, you lose IntelliSense and compile-time type checking. An error in the field name will only show up at runtime. Therefore:
- \n
- Use
dynamiconly for reading data you don't control. \n - Always wrap calls in try-catch blocks. \n
- Don't overuse it — if the JSON structure is stable, it's better to create a DTO class. \n
Method 2: The Modern — System.Text.Json
\n\nStarting with .NET Core 3.0, Microsoft promotes System.Text.Json — fast, native, with no external dependencies. In 2025, it's the standard for new projects.
But there's a catch: System.Text.Json doesn't support deserializing into dynamic out of the box. You'll need to get a bit creative.
Option A: Via JsonDocument and ExpandoObject
\n\nusing System.Text.Json;\nusing System.Dynamic;\n\nstring json = @"{""name"":""Elena"",""age"":25,""active"":true}";\n\nusing JsonDocument doc = JsonDocument.Parse(json);\ndynamic obj = ConvertToExpando(doc.RootElement);\n\nConsole.WriteLine(obj.name); // Elena\nConsole.WriteLine(obj.age); // 25\nConsole.WriteLine(obj.active); // True\n\nstatic ExpandoObject ConvertToExpando(JsonElement element)\n{\n var expando = new ExpandoObject();\n var dict = (IDictionary<string, object>)expando;\n\n foreach (var property in element.Enumera