Deserialize JSON into C# dynamic object?

971,111

Solution 1

If you are happy to have a dependency upon the System.Web.Helpers assembly, then you can use the Json class:

dynamic data = Json.Decode(json);

It is included with the MVC framework as an additional download to the .NET 4 framework. Be sure to give Vlad an upvote if that's helpful! However if you cannot assume the client environment includes this DLL, then read on.


An alternative deserialisation approach is suggested here. I modified the code slightly to fix a bug and suit my coding style. All you need is this code and a reference to System.Web.Extensions from your project:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Dynamic;
using System.Linq;
using System.Text;
using System.Web.Script.Serialization;

public sealed class DynamicJsonConverter : JavaScriptConverter
{
    public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
    {
        if (dictionary == null)
            throw new ArgumentNullException("dictionary");

        return type == typeof(object) ? new DynamicJsonObject(dictionary) : null;
    }

    public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override IEnumerable<Type> SupportedTypes
    {
        get { return new ReadOnlyCollection<Type>(new List<Type>(new[] { typeof(object) })); }
    }

    #region Nested type: DynamicJsonObject

    private sealed class DynamicJsonObject : DynamicObject
    {
        private readonly IDictionary<string, object> _dictionary;

        public DynamicJsonObject(IDictionary<string, object> dictionary)
        {
            if (dictionary == null)
                throw new ArgumentNullException("dictionary");
            _dictionary = dictionary;
        }

        public override string ToString()
        {
            var sb = new StringBuilder("{");
            ToString(sb);
            return sb.ToString();
        }

        private void ToString(StringBuilder sb)
        {
            var firstInDictionary = true;
            foreach (var pair in _dictionary)
            {
                if (!firstInDictionary)
                    sb.Append(",");
                firstInDictionary = false;
                var value = pair.Value;
                var name = pair.Key;
                if (value is string)
                {
                    sb.AppendFormat("{0}:\"{1}\"", name, value);
                }
                else if (value is IDictionary<string, object>)
                {
                    new DynamicJsonObject((IDictionary<string, object>)value).ToString(sb);
                }
                else if (value is ArrayList)
                {
                    sb.Append(name + ":[");
                    var firstInArray = true;
                    foreach (var arrayValue in (ArrayList)value)
                    {
                        if (!firstInArray)
                            sb.Append(",");
                        firstInArray = false;
                        if (arrayValue is IDictionary<string, object>)
                            new DynamicJsonObject((IDictionary<string, object>)arrayValue).ToString(sb);
                        else if (arrayValue is string)
                            sb.AppendFormat("\"{0}\"", arrayValue);
                        else
                            sb.AppendFormat("{0}", arrayValue);

                    }
                    sb.Append("]");
                }
                else
                {
                    sb.AppendFormat("{0}:{1}", name, value);
                }
            }
            sb.Append("}");
        }

        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            if (!_dictionary.TryGetValue(binder.Name, out result))
            {
                // return null to avoid exception.  caller can check for null this way...
                result = null;
                return true;
            }

            result = WrapResultObject(result);
            return true;
        }

        public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
        {
            if (indexes.Length == 1 && indexes[0] != null)
            {
                if (!_dictionary.TryGetValue(indexes[0].ToString(), out result))
                {
                    // return null to avoid exception.  caller can check for null this way...
                    result = null;
                    return true;
                }

                result = WrapResultObject(result);
                return true;
            }

            return base.TryGetIndex(binder, indexes, out result);
        }

        private static object WrapResultObject(object result)
        {
            var dictionary = result as IDictionary<string, object>;
            if (dictionary != null)
                return new DynamicJsonObject(dictionary);

            var arrayList = result as ArrayList;
            if (arrayList != null && arrayList.Count > 0)
            {
                return arrayList[0] is IDictionary<string, object> 
                    ? new List<object>(arrayList.Cast<IDictionary<string, object>>().Select(x => new DynamicJsonObject(x))) 
                    : new List<object>(arrayList.Cast<object>());
            }

            return result;
        }
    }

    #endregion
}

You can use it like this:

string json = ...;

var serializer = new JavaScriptSerializer();
serializer.RegisterConverters(new[] { new DynamicJsonConverter() });

dynamic obj = serializer.Deserialize(json, typeof(object));

So, given a JSON string:

{
  "Items":[
    { "Name":"Apple", "Price":12.3 },
    { "Name":"Grape", "Price":3.21 }
  ],
  "Date":"21/11/2010"
}

The following code will work at runtime:

dynamic data = serializer.Deserialize(json, typeof(object));

data.Date; // "21/11/2010"
data.Items.Count; // 2
data.Items[0].Name; // "Apple"
data.Items[0].Price; // 12.3 (as a decimal)
data.Items[1].Name; // "Grape"
data.Items[1].Price; // 3.21 (as a decimal)

Solution 2

It's pretty simple using Json.NET:

dynamic stuff = JsonConvert.DeserializeObject("{ 'Name': 'Jon Smith', 'Address': { 'City': 'New York', 'State': 'NY' }, 'Age': 42 }");

string name = stuff.Name;
string address = stuff.Address.City;

Also using Newtonsoft.Json.Linq:

dynamic stuff = JObject.Parse("{ 'Name': 'Jon Smith', 'Address': { 'City': 'New York', 'State': 'NY' }, 'Age': 42 }");

string name = stuff.Name;
string address = stuff.Address.City;

Documentation: Querying JSON with dynamic

Solution 3

You can do this using System.Web.Helpers.Json - its Decode method returns a dynamic object which you can traverse as you like.

It's included in the System.Web.Helpers assembly (.NET 4.0).

var dynamicObject = Json.Decode(jsonString);

Solution 4

.NET 4.0 has a built-in library to do this:

using System.Web.Script.Serialization;
JavaScriptSerializer jss = new JavaScriptSerializer();
var d = jss.Deserialize<dynamic>(str);

This is the simplest way.

Solution 5

Simple "string JSON data" to object without any third-party DLL file:

WebClient client = new WebClient();
string getString = client.DownloadString("https://graph.facebook.com/zuck");

JavaScriptSerializer serializer = new JavaScriptSerializer();
dynamic item = serializer.Deserialize<object>(getString);
string name = item["name"];

//note: JavaScriptSerializer in this namespaces
//System.Web.Script.Serialization.JavaScriptSerializer

Note: You can also using your custom object.

Personel item = serializer.Deserialize<Personel>(getString);
Share:
971,111
jswanson
Author by

jswanson

Updated on December 23, 2021

Comments

  • jswanson
    jswanson over 2 years

    Is there a way to deserialize JSON content into a C# dynamic type? It would be nice to skip creating a bunch of classes in order to use the DataContractJsonSerializer.

    • Admin
      Admin almost 14 years
      If you want something 'dynamic', why not just use the get-style accessors that come with most JSON decoders that don't go to plain-old-object? (e.g. is there really a need for 'dynamic' object creation?) json.org has a bunch of links for C# JSON implementations.
    • jswanson
      jswanson almost 14 years
      I'm working on a project that is trying to keep external dependencies to a minimum. So if it's possible to something with the stock .net serializers and types that would be preferred. Of course if it's not possible I'm hitting up json.org. Thanks!
    • Frank Schwieterman
      Frank Schwieterman almost 14 years
      I'm really surprised the C# team added 'dynamic' but then there is no way in the CLR to convert a JSON object to a dynamic CLR class instance.
    • Drew Noakes
      Drew Noakes over 13 years
      Unfortunately the accepted answer doesn't work in .NET 4 RTM. I posted an answer that helped me get going with this which might be useful to others.
    • Ole EH Dufour
      Ole EH Dufour over 5 years
      Update October 2018, this is how the magic happens: stackoverflow.com/a/48023576/4180382
  • Mark Dickinson
    Mark Dickinson over 13 years
    Thanks Drew, your TryGetMember sorted my issue around recursing into nested collections, but could you perhaps let us know what it is that makes it work. Is it in the fact that array lists are cast into IDictionary and then projected as DynamicJsonObjects, rather than being projected as arrayList members? Hope this isn't a too dumb question. Thanks for the answer :)
  • Drew Noakes
    Drew Noakes over 13 years
    @Mark, it's been a while since I looked at this but from memory what you're describing sounds right.
  • jswanson
    jswanson about 13 years
    Most of the previous answers came before .NET 4.0 RTM.
  • mitaka
    mitaka about 13 years
    have you tried this? It returns Dictionary<string,object>. Unless I'm missing something, your example does not return a dynamic object.
  • Peter Long
    Peter Long about 13 years
    @sergiopereira yes I did. you can cast any type to dynamic type. so why not just do a cast?
  • Stewie Griffin
    Stewie Griffin about 13 years
    I get an error in dynamic obj = serializer.Deserialize(json, typeof(object)); saying that no overload for method with 2 arguments..wrong dll or what?
  • Drew Noakes
    Drew Noakes about 13 years
    @Stewie, the type I'm using is System.Web.Script.Serialization.JavaScriptSerializer which is in version 4.0.0.0 of System.Web.dll.
  • mattmanser
    mattmanser almost 13 years
    This doesn't work, it just return a dict in the form of a dynamic
  • Peter Long
    Peter Long almost 13 years
    @mattmanser, please learn what is dynamic. every dynamic type would be resolved to a static type finally.
  • mattmanser
    mattmanser almost 13 years
    @Peter Long I believe I have failed to state my case clearly, dear fellow. Let me attempt to rectify my error. I know what a dynamic is. This doesn't allow you to pass in a JSON object and use d.code, you'd have to do d["code"].Value, which isn't what most people finding this answer want, we already know how to get the dictionary and casting it to a dynamic is a total waste of time. I respectfully disagree, sir.
  • Peter Long
    Peter Long almost 13 years
    @mattmanser, we already know how to get the dictionary and casting it to a dynamic. It does not have to be a dictionay. Json also have lists besides dictionary. And also lists and dictionaries could be nested. My code could handle all of these situations. BUT your method can NOT.
  • Peter Long
    Peter Long almost 13 years
    @mattmanser, instead of d["code"].Value, you want d.code. As far as I know, it is impossible(or meaningless). Think of dynamic as deferring part of the compiler’s job to runtime. That's what dynamic is useful for. Dynamic is not mean to solve your problem.
  • Rush Frisby
    Rush Frisby over 12 years
    System.Web.Script.Serialization.JavaScriptSerializer is in System.Web.Extensions.dll - goo.gl/8zRrj
  • Quantumplation
    Quantumplation over 12 years
    I found that your ToString method wasn't working for me, so I rewrote it. It might have some bugs, but it's working over my dataset, so I'll provide it here for anyone else who might be having trouble with this: pastebin.com/BiRmQZdz
  • Drew Noakes
    Drew Noakes over 12 years
    @Tim, I can't see why not, but I'm not familiar enough with VB.NET to convert the code for you. You could compile the C# code and use it via an assembly reference, or try to convert it yourself. I don't think it would be too hard to convert.
  • Timuçin
    Timuçin over 12 years
    Yes, I already used the c# assembly, but it is still the same. This "dynamic" object detection didnt work. In my case, "data" is an array of Objects that each of them includes key-value pair for json data.
  • Vlad Iliescu
    Vlad Iliescu over 12 years
    You can use System.Web.Helpers.Json - it offers a Decode method that returns a dynamic object. I've also posted this info as an answer.
  • jbtule
    jbtule about 12 years
    FYI System.Web.Helpers.dll requires .net 4.0 but is not included in .net 4.0. It can be installed with ASP.NET MVC 3
  • Radu Simionescu
    Radu Simionescu over 11 years
    sometimes in js you have fields with special chars like "background-color". To access such fields in js you do obj["background-color"]. How can I access such fields from c# after deserializing to dynamic object? I can't do obj.background-color, of course, and obj["background-color"] doesn't seem to work. It would be nice if the dynamic object could also be accessed as a dictionary, at the same time, exactly like in js.
  • Drew Noakes
    Drew Noakes over 11 years
    @RaduSimionescu, have you tried swapping the hyphen for an underscore? I haven't tried it myself, but I recall something somewhere about this.
  • W3Max
    W3Max over 11 years
    You will find this assembly in the Extensions group under Assemblies in Visual Studio 2012
  • Martin Ender
    Martin Ender over 11 years
    @RaduSimionescu I am probably a bit late, but maybe this helps future visitors. I had the same problem, just with the field-name params (which is a keyword in C#). In addition to TryGetMember you can override TryGetIndex, which gives you exactly the same behavior as in JS. Then you can do obj["params"] or obj["background-color"] for awkward field names.
  • cikatomo
    cikatomo over 11 years
    Id don't get it. This is by far most simple solution and nobody mentions it.
  • Usama Khalil
    Usama Khalil about 11 years
    Any Issues with using dynamic ? How can we handle exceptions efficiently if input JSON does not contain the properties..
  • Mike
    Mike about 11 years
    If you're wanting to strongly type the model then be sure to use the Json.Decode<T>(string) method.
  • İbrahim Özbölük
    İbrahim Özbölük almost 11 years
    yes it's simple :) sometime you need serialize but don't want to include 3rd part dll
  • Royi Namir
    Royi Namir almost 11 years
    Can you elaborate on : how dynamic can access the DEserialized object via : myObject["myprop"] ? I know it's done on runtime but how accessing it via myObject["myprop"] is valid ?
  • İbrahim Özbölük
    İbrahim Özbölük almost 11 years
    You can deserialize your object like Personel item = serializer.Deserialize<Personel>(getString); and if you use dynamic object also you can using array and everything is possible like everyobject
  • Dexter Legaspi
    Dexter Legaspi over 10 years
    this is simple and direct-to-the-point answer...**and it works**. While there are 3rd party libraries that are more full-featured and more efficient (ServiceStack comes to mind, NOT the overrated and super-bloated JSON.NET libraries), sometimes it's better to have the native option (which is available since .NET 4.x) if you don't necessarily need the speed...also, @mattmanser is wrong on all counts; he doesn't seem to grasp what dynamic types are at the time he posted his comments.
  • Vyache
    Vyache over 10 years
    Interesting, using MVC, how do I bind this to the view? I read through a few posts about dynamic or anonymous type bind, but I'm not seeing an example of how to use it. Say I have json that may have a lot of layers.
  • Hot Licks
    Hot Licks about 10 years
    How can you introspect the dynamic stuff?
  • Matthias
    Matthias about 10 years
    @HotLicks: To introspect the dynamic stuff do something like: foreach (Newtonsoft.Json.Linq.JProperty jproperty in stuff) { Console.WriteLine("jproperty.Name = {0}", jproperty.Name);}
  • Admin
    Admin almost 10 years
    To add this library to your project: stackoverflow.com/questions/8037895/…
  • cja
    cja over 9 years
    What's the difference between JsonConvert.DeserializeObject and JObject.Parse ? The answer is using them both in the same way to do the same thing but doesn't explain the difference.
  • Stephen Drew
    Stephen Drew over 9 years
    @mattmanser is right; it is possible to implement IDynamicMetaObjectProvider (or use e.g. ExpandoObject) that is able to intercept properties and look them up in an internal dictionary. This combined with the use of dynamic allows code such as d.code to be used. It's kind of pointless to cast a dictionary to a dynamic.
  • Lee Louviere
    Lee Louviere over 9 years
    @TomPeplow Tried this. It didn't work for me. It says that "JObject doesn't implement 'Name'".
  • nawfal
    nawfal about 9 years
    I upvoted this answer even though the answer doesnt strictly return a IDynamicMetaObjectProvider object. I mean it's useful for people who dont strictly want it to be dynamic. The OP states he wants to avoid creating custom classes and attributes and this answer helps. Peter Long could have been more clear about that in his answer, though. Can I edit this answer?
  • nawfal
    nawfal about 9 years
  • codeConcussion
    codeConcussion over 8 years
    I can't get this to work. I've narrowed the issue down to being inside an async method. If I make the method synchronous it works as expected. However, make the method async and I can't get a dynamic, I just get an object. Explicit casting does nothing, still just gives me an object. Is anyone else experiencing this?
  • Illuminati
    Illuminati about 8 years
    but that's not what the question is asking about. there's a different when you have to specify the type for every json string and working with dynamic type.
  • Michael Blackburn
    Michael Blackburn almost 8 years
    @codeConcussion It is possible some people having issues are missing a reference to Microsoft.CSharp? dynamic requires this reference (as does async -- I might be wrong there)
  • Mahesh
    Mahesh over 7 years
    System.Web.Helpers could be downloaded in VS2015 using Package Manage Console with this command: Install-Package System-Web-Helpers.dll Also, Json in System.Web.Mvc conflicts with Json in System.Web.Helpers. So you can use dynamic data = System.Web.Helpers.Json.Decode(myJSONString);
  • starmandeluxe
    starmandeluxe over 6 years
    FYI If you're using .NET Core, they moved this thing into the "microsoft-web-helpers" package.
  • LanchPad
    LanchPad almost 6 years
    The discussion above is a result of confusion between a 'dynamic' variable declaration (@PeterLong's topic) and the 'DynamicObject' type (@mattmanser's desired result). For details on both see the documentation (as always): docs.microsoft.com/en-us/dotnet/csharp/programming-guide/typ‌​es/… docs.microsoft.com/en-us/dotnet/csharp/programming-guide/typ‌​es/…
  • StilgarISCA
    StilgarISCA almost 6 years
    To use the System.Web.Script.Serialization namespace your project needs a reference to System.Web.Extensions.
  • syonip
    syonip over 5 years
    to use System.Web.Helpers you need to add a nuget package: nuget.org/packages/microsoft-web-helpers
  • davidthegrey
    davidthegrey over 5 years
    I would use Newtonsoft Json but documentation is very poor. Lacks a lot in examples. I would need to know how to deal with arrays, how to deal with subobjects as properties, how to check if a property exists, how the json value types (integers, decimals, boolean, null) are converted in c#... One simple sample would be enough, but really looks like I am looking for the weirdest thing.
  • Lucio M. Tato
    Lucio M. Tato almost 5 years
    If you can't make it work, try this: dynamic v = JsonConvert.DeserializeObject<ExpandoObject>(someJSONstring)‌​;
  • Andrei U
    Andrei U almost 5 years
    @codeConcussion had the same issue with the async method that retrieves an object rather than a dynamic. to fix it simply do an explicit cast to dynamic and you're OK (myresult as dynamic).
  • Alex 75
    Alex 75 over 4 years
    This approach allow to "traverse" the jSON document, so that you can manage situation where the JSON structure is unknown or variable (for example, many API returns a completely different JSON document when an error occurs). There are other libraries that permits to do that, apart from Newtonsoft.JSON (aka JSON.NET) ?
  • Etienne
    Etienne over 4 years
    In my case this returns a Dictionary<string,object>. I cannot access any of the keys if the object is dynamic, I have to explicitly cast it as dictionary.
  • jsiot
    jsiot over 4 years
    this saved me a lot of time ! should be chosen as best answer !
  • zolty13
    zolty13 about 4 years
    nuget.org/packages/microsoft-web-helpers cause error: System.IO.FileNotFoundException File name: 'System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' at System.Web.Helpers.Json.Decode(String value)
  • Mandar Jogalekar
    Mandar Jogalekar almost 4 years
    best solution on this page.
  • Pang
    Pang over 3 years
    Last link in answer is dead - "403 Site Disabled | This site is stopped".
  • Fandango68
    Fandango68 over 3 years
    Yeah but how do you use it? Poorly answered
  • vt100
    vt100 over 3 years
    data.Items.Count didn't work for me - data.Items.Length did.
  • RainCast
    RainCast about 3 years
    visual studio didn't recognize Json class even after added using System.Web.Helpers;
  • singhswat
    singhswat about 3 years
    An example will help wider audience
  • znn
    znn about 3 years
    My favourite method so far
  • Shahroozevsky
    Shahroozevsky almost 3 years
    dude, +1 hug for you :D
  • stuzor
    stuzor almost 3 years
    I think the VS debugger Watch window fails to retrieve properties when called inside an async method. Works fine from a non-async method
  • Vidar
    Vidar over 2 years
    I don't understand why this answer is above the one with over 700 upvotes and marked as correct answer!?
  • Daniel Earwicker
    Daniel Earwicker over 2 years
    @Vidar are you sorting by Oldest instead of by Votes?
  • Techiemanu
    Techiemanu over 2 years
  • Anirudha Gupta
    Anirudha Gupta over 2 years
    It's not working in .net 6, Any idea?. I want to read property which have array of elements.
  • Tengiz
    Tengiz over 2 years
    It will only work for the primitive type properties because the expando object handles the property read by name and returns the value as-is. The thing is that the Console.WriteLine converts the value to the string by calling ToString which for the primitive types will give the correct value. For the array, you will perhaps see not the actual value but the object type in the output.