Deserialize JSON into C# dynamic object? [duplicate]
Asked Answered
F

31

1183

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.

Firstfoot answered 29/6, 2010 at 16:4 Comment(4)
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.Within
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!Firstfoot
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.Chaffin
You should be aware thing I tumbled on: I was really lucky I found this great thread only after I already had created the class in Visual Studio using Edit >'Paste Special'->'Paste JSON as Classes'. Creating the class like that enabled the intellisense work perfectly for the given json structure. This was absolutely necessary as the json string was huge -370k. It is big info dump about youtube video using "ytdlp --dump-json" having tens of json items.Anew
P
735

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)
Panada answered 27/9, 2010 at 17:46 Comment(19)
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 :)Craunch
@Mark, it's been a while since I looked at this but from memory what you're describing sounds right.Panada
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?Subauricular
@Stewie, the type I'm using is System.Web.Script.Serialization.JavaScriptSerializer which is in version 4.0.0.0 of System.Web.dll.Panada
System.Web.Script.Serialization.JavaScriptSerializer is in System.Web.Extensions.dll - goo.gl/8zRrjAssignat
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/BiRmQZdzAhvenanmaa
@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.Panada
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.Blacksnake
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.Lavenialaver
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.Numidia
@RaduSimionescu, have you tried swapping the hyphen for an underscore? I haven't tried it myself, but I recall something somewhere about this.Panada
@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.Bedplate
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);Lightless
FYI If you're using .NET Core, they moved this thing into the "microsoft-web-helpers" package.Pforzheim
to use System.Web.Helpers you need to add a nuget package: nuget.org/packages/microsoft-web-helpersFraser
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)Homophonic
Last link in answer is dead - "403 Site Disabled | This site is stopped".Fredette
data.Items.Count didn't work for me - data.Items.Length did.Astonied
visual studio didn't recognize Json class even after added using System.Web.Helpers;Salita
G
751

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

Gaga answered 17/2, 2012 at 9:56 Comment(12)
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.Baywood
How can you introspect the dynamic stuff?Behlau
@HotLicks: To introspect the dynamic stuff do something like: foreach (Newtonsoft.Json.Linq.JProperty jproperty in stuff) { Console.WriteLine("jproperty.Name = {0}", jproperty.Name);}Heteromorphic
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.Balas
@TomPeplow Tried this. It didn't work for me. It says that "JObject doesn't implement 'Name'".Gittel
@Balas no difference: #23645534Kenlee
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?Dustcloth
@Dustcloth 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)Pittance
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.Darwin
If you can't make it work, try this: dynamic v = JsonConvert.DeserializeObject<ExpandoObject>(someJSONstring);Learned
@Dustcloth 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).Artificial
I think the VS debugger Watch window fails to retrieve properties when called inside an async method. Works fine from a non-async methodChemo
P
735

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)
Panada answered 27/9, 2010 at 17:46 Comment(19)
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 :)Craunch
@Mark, it's been a while since I looked at this but from memory what you're describing sounds right.Panada
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?Subauricular
@Stewie, the type I'm using is System.Web.Script.Serialization.JavaScriptSerializer which is in version 4.0.0.0 of System.Web.dll.Panada
System.Web.Script.Serialization.JavaScriptSerializer is in System.Web.Extensions.dll - goo.gl/8zRrjAssignat
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/BiRmQZdzAhvenanmaa
@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.Panada
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.Blacksnake
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.Lavenialaver
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.Numidia
@RaduSimionescu, have you tried swapping the hyphen for an underscore? I haven't tried it myself, but I recall something somewhere about this.Panada
@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.Bedplate
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);Lightless
FYI If you're using .NET Core, they moved this thing into the "microsoft-web-helpers" package.Pforzheim
to use System.Web.Helpers you need to add a nuget package: nuget.org/packages/microsoft-web-helpersFraser
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)Homophonic
Last link in answer is dead - "403 Site Disabled | This site is stopped".Fredette
data.Items.Count didn't work for me - data.Items.Length did.Astonied
visual studio didn't recognize Json class even after added using System.Web.Helpers;Salita
L
311

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);
Lavenialaver answered 29/2, 2012 at 7:28 Comment(5)
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 3Jeanajeanbaptiste
You will find this assembly in the Extensions group under Assemblies in Visual Studio 2012Soniasonic
Any Issues with using dynamic ? How can we handle exceptions efficiently if input JSON does not contain the properties..Romelda
If you're wanting to strongly type the model then be sure to use the Json.Decode<T>(string) method.Anthotaxy
To add this library to your project: #8038395Triumph
P
89

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);
Paramedic answered 30/11, 2012 at 10:1 Comment(7)
Id don't get it. This is by far most simple solution and nobody mentions it.Instill
yes it's simple :) sometime you need serialize but don't want to include 3rd part dllRoa
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 ?Eindhoven
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 everyobjectRoa
To use the System.Web.Script.Serialization namespace your project needs a reference to System.Web.Extensions.Kaciekacy
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.Rosetterosewall
best solution on this page.Selfstarter
M
87

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

Marinemarinelli answered 12/6, 2011 at 11:32 Comment(12)
Most of the previous answers came before .NET 4.0 RTM.Firstfoot
have you tried this? It returns Dictionary<string,object>. Unless I'm missing something, your example does not return a dynamic object.Olson
@Olson yes I did. you can cast any type to dynamic type. so why not just do a cast?Marinemarinelli
This doesn't work, it just return a dict in the form of a dynamicSpicy
@mattmanser, please learn what is dynamic. every dynamic type would be resolved to a static type finally.Marinemarinelli
@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.Spicy
@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.Marinemarinelli
@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.Marinemarinelli
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, @Spicy is wrong on all counts; he doesn't seem to grasp what dynamic types are at the time he posted his comments.Dennet
@Spicy 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.Engelbert
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?Kenlee
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): learn.microsoft.com/en-us/dotnet/csharp/programming-guide/types/… learn.microsoft.com/en-us/dotnet/csharp/programming-guide/types/…Brittaneybrittani
E
46

You can achieve that with the help of Newtonsoft.Json. Install it from NuGet and then:

using Newtonsoft.Json;

dynamic results = JsonConvert.DeserializeObject<dynamic>(YOUR_JSON);
Eraser answered 2/8, 2019 at 8:22 Comment(0)
I
38

I came here to find an answer for .NET Core, without any third-party or additional references. It works fine if you use ExpandoObject with the standard JsonSerializer class. Here is the example that worked for me:

using System.Text.Json;
using System.Dynamic;

dynamic json = JsonSerializer.Deserialize<ExpandoObject>(jsonText);
Console.WriteLine(json.name);

This code prints out the string value of a name property that exists within the JSON text passed into the Deserialize method. Voila - no additional libraries, no nothing. Just .NET core.

Edit: May have a problem for several levels of json with nested elements. Worked for a single-level flat object.

Isidora answered 22/12, 2021 at 18:51 Comment(3)
It's not working in .net 6, Any idea?. I want to read property which have array of elements.Standpoint
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.Isidora
Note that using ExpandoObject is expensive!Centaury
J
29

JsonFx can deserialize JSON content into dynamic objects.

Serialize to/from dynamic types (default for .NET 4.0):

var reader = new JsonReader(); var writer = new JsonWriter();

string input = @"{ ""foo"": true, ""array"": [ 42, false, ""Hello!"", null ] }";
dynamic output = reader.Read(input);
Console.WriteLine(output.array[0]); // 42
string json = writer.Write(output);
Console.WriteLine(json); // {"foo":true,"array":[42,false,"Hello!",null]}
Jeanajeanbaptiste answered 2/3, 2011 at 1:27 Comment(0)
C
26

Another way using Newtonsoft.Json:

dynamic stuff = Newtonsoft.Json.JsonConvert.DeserializeObject("{ color: 'red', value: 5 }");
string color = stuff.color;
int value = stuff.value;
Crate answered 9/4, 2013 at 19:19 Comment(0)
S
20

I made a new version of the DynamicJsonConverter that uses Expando Objects. I used expando objects, because I wanted to Serialize the dynamic back into JSON using Json.NET.

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

public static class DynamicJson
{
    public static dynamic Parse(string json)
    {
        JavaScriptSerializer jss = new JavaScriptSerializer();
        jss.RegisterConverters(new JavaScriptConverter[] { new DynamicJsonConverter() });

        dynamic glossaryEntry = jss.Deserialize(json, typeof(object)) as dynamic;
        return glossaryEntry;
    }

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

            var result = ToExpando(dictionary);

            return type == typeof(object) ? result : null;
        }

        private static ExpandoObject ToExpando(IDictionary<string, object> dictionary)
        {
            var result = new ExpandoObject();
            var dic = result as IDictionary<String, object>;

            foreach (var item in dictionary)
            {
                var valueAsDic = item.Value as IDictionary<string, object>;
                if (valueAsDic != null)
                {
                    dic.Add(item.Key, ToExpando(valueAsDic));
                    continue;
                }
                var arrayList = item.Value as ArrayList;
                if (arrayList != null && arrayList.Count > 0)
                {
                    dic.Add(item.Key, ToExpando(arrayList));
                    continue;
                }

                dic.Add(item.Key, item.Value);
            }
            return result;
        }

        private static ArrayList ToExpando(ArrayList obj)
        {
            ArrayList result = new ArrayList();

            foreach (var item in obj)
            {
                var valueAsDic = item as IDictionary<string, object>;
                if (valueAsDic != null)
                {
                    result.Add(ToExpando(valueAsDic));
                    continue;
                }

                var arrayList = item as ArrayList;
                if (arrayList != null && arrayList.Count > 0)
                {
                    result.Add(ToExpando(arrayList));
                    continue;
                }

                result.Add(item);
            }
            return result;
        }

        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) })); }
        }
    }
}
Sadiras answered 7/6, 2011 at 7:31 Comment(0)
F
14

Creating dynamic objects with Newtonsoft.Json works really great.

//json is your string containing the JSON value
dynamic data = JsonConvert.DeserializeObject<dynamic>(json);

Now you can access the data object just like if it was a regular object. This is the JSON object we currently have as an example:

{ "ID":123,"Name":"Jack","Numbers":[1, 2, 3] }

This is how you access it after deserialization:

data.ID //Retrieve the int
data.Name //Retrieve the string
data.Numbers[0] //Retrieve the first element in the array
Fortenberry answered 17/8, 2020 at 19:21 Comment(0)
F
12

I use http://json2csharp.com/ to get a class representing the JSON object.

Input:

{
   "name":"John",
   "age":31,
   "city":"New York",
   "Childs":[
      {
         "name":"Jim",
         "age":11
      },
      {
         "name":"Tim",
         "age":9
      }
   ]
}

Output:

public class Child
{
    public string name { get; set; }
    public int age { get; set; }
}

public class Person
{
    public string name { get; set; }
    public int age { get; set; }
    public string city { get; set; }
    public List<Child> Childs { get; set; }
}

After that I use Newtonsoft.Json to fill the class:

using Newtonsoft.Json;

namespace GitRepositoryCreator.Common
{
    class JObjects
    {
        public static string Get(object p_object)
        {
            return JsonConvert.SerializeObject(p_object);
        }
        internal static T Get<T>(string p_object)
        {
            return JsonConvert.DeserializeObject<T>(p_object);
        }
    }
}

You can call it like this:

Person jsonClass = JObjects.Get<Person>(stringJson);

string stringJson = JObjects.Get(jsonClass);

PS:

If your JSON variable name is not a valid C# name (name starts with $) you can fix that like this:

public class Exception
{
   [JsonProperty(PropertyName = "$id")]
   public string id { get; set; }
   public object innerException { get; set; }
   public string message { get; set; }
   public string typeName { get; set; }
   public string typeKey { get; set; }
   public int errorCode { get; set; }
   public int eventId { get; set; }
}
Freeboard answered 10/6, 2017 at 16:40 Comment(0)
W
8

The simplest way is:

Just include this DLL file.

Use the code like this:

dynamic json = new JDynamic("{a:'abc'}");
// json.a is a string "abc"

dynamic json = new JDynamic("{a:3.1416}");
// json.a is 3.1416m

dynamic json = new JDynamic("{a:1}");
// json.a is

dynamic json = new JDynamic("[1,2,3]");
/json.Length/json.Count is 3
// And you can use json[0]/ json[2] to get the elements

dynamic json = new JDynamic("{a:[1,2,3]}");
//json.a.Length /json.a.Count is 3.
// And you can use  json.a[0]/ json.a[2] to get the elements

dynamic json = new JDynamic("[{b:1},{c:1}]");
// json.Length/json.Count is 2.
// And you can use the  json[0].b/json[1].c to get the num.
Warhol answered 26/12, 2012 at 11:15 Comment(0)
L
8

Another option is to "Paste JSON as classes" so it can be deserialised quick and easy.

  1. Simply copy your entire JSON
  2. In Visual Studio: Click EditPaste SpecialPaste JSON as classes

Here is a better explanation n piccas... ‘Paste JSON As Classes’ in ASP.NET and Web Tools 2012.2 RC

Lablab answered 17/3, 2018 at 3:55 Comment(0)
I
6

You can extend the JavaScriptSerializer to recursively copy the dictionary it created to expando object(s) and then use them dynamically:

static class JavaScriptSerializerExtensions
{
    public static dynamic DeserializeDynamic(this JavaScriptSerializer serializer, string value)
    {
        var dictionary = serializer.Deserialize<IDictionary<string, object>>(value);
        return GetExpando(dictionary);
    }

    private static ExpandoObject GetExpando(IDictionary<string, object> dictionary)
    {
        var expando = (IDictionary<string, object>)new ExpandoObject();

        foreach (var item in dictionary)
        {
            var innerDictionary = item.Value as IDictionary<string, object>;
            if (innerDictionary != null)
            {
                expando.Add(item.Key, GetExpando(innerDictionary));
            }
            else
            {
                expando.Add(item.Key, item.Value);
            }
        }

        return (ExpandoObject)expando;
    }
}

Then you just need to having a using statement for the namespace you defined the extension in (consider just defining them in System.Web.Script.Serialization... another trick is to not use a namespace, then you don't need the using statement at all) and you can consume them like so:

var serializer = new JavaScriptSerializer();
var value = serializer.DeserializeDynamic("{ 'Name': 'Jon Smith', 'Address': { 'City': 'New York', 'State': 'NY' }, 'Age': 42 }");

var name = (string)value.Name; // Jon Smith
var age = (int)value.Age;      // 42

var address = value.Address;
var city = (string)address.City;   // New York
var state = (string)address.State; // NY
Imprint answered 30/11, 2011 at 21:51 Comment(0)
C
6

Try this:

  var units = new { Name = "Phone", Color= "White" };
    var jsonResponse = JsonConvert.DeserializeAnonymousType(json, units);
Claudy answered 7/3, 2015 at 8:47 Comment(2)
My favourite method so farIceberg
dude, +1 hug for you :DCanopus
E
6

You can use using Newtonsoft.Json

var jRoot = 
 JsonConvert.DeserializeObject<dynamic>(Encoding.UTF8.GetString(resolvedEvent.Event.Data));

resolvedEvent.Event.Data is my response getting from calling core Event .

Encyclopedic answered 26/6, 2017 at 9:18 Comment(0)
K
6

I want to do this programmatically in unit tests, I do have the luxury of typing it out.

My solution is:

var dict = JsonConvert.DeserializeObject<ExpandoObject>(json) as IDictionary<string, object>;

Now I can assert that

dict.ContainsKey("ExpectedProperty");
Kovacev answered 23/9, 2020 at 11:6 Comment(0)
N
5

Look at the article I wrote on CodeProject, one that answers the question precisely:

Dynamic types with JSON.NET

There is way too much for re-posting it all here, and even less point since that article has an attachment with the key/required source file.

Nullity answered 4/8, 2013 at 19:12 Comment(0)
A
5

Deserializing in JSON.NET can be dynamic using the JObject class, which is included in that library. My JSON string represents these classes:

public class Foo {
   public int Age {get;set;}
   public Bar Bar {get;set;}
}

public class Bar {
   public DateTime BDay {get;set;}
}

Now we deserialize the string WITHOUT referencing the above classes:

var dyn = JsonConvert.DeserializeObject<JObject>(jsonAsFooString);

JProperty propAge = dyn.Properties().FirstOrDefault(i=>i.Name == "Age");
if(propAge != null) {
    int age = int.Parse(propAge.Value.ToString());
    Console.WriteLine("age=" + age);
}

//or as a one-liner:
int myage = int.Parse(dyn.Properties().First(i=>i.Name == "Age").Value.ToString());

Or if you want to go deeper:

var propBar = dyn.Properties().FirstOrDefault(i=>i.Name == "Bar");
if(propBar != null) {
    JObject o = (JObject)propBar.First();
    var propBDay = o.Properties().FirstOrDefault (i => i.Name=="BDay");
    if(propBDay != null) {
        DateTime bday = DateTime.Parse(propBDay.Value.ToString());
        Console.WriteLine("birthday=" + bday.ToString("MM/dd/yyyy"));
    }
}

//or as a one-liner:
DateTime mybday = DateTime.Parse(((JObject)dyn.Properties().First(i=>i.Name == "Bar").First()).Properties().First(i=>i.Name == "BDay").Value.ToString());

See post for a complete example.

Await answered 30/7, 2015 at 15:29 Comment(1)
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) ?Janessa
C
5

I am using like this in my code and it's working fine

using System.Web.Script.Serialization;
JavaScriptSerializer oJS = new JavaScriptSerializer();
RootObject oRootObject = new RootObject();
oRootObject = oJS.Deserialize<RootObject>(Your JSon String);
Christos answered 10/8, 2015 at 20:8 Comment(1)
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.Kiyohara
U
4

For that I would use JSON.NET to do the low-level parsing of the JSON stream and then build up the object hierarchy out of instances of the ExpandoObject class.

Umbrian answered 29/6, 2010 at 16:7 Comment(1)
An example will help wider audienceDomeniga
S
4

The object you want DynamicJSONObject is included in the System.Web.Helpers.dll from the ASP.NET Web Pages package, which is part of WebMatrix.

Schenck answered 20/12, 2010 at 16:16 Comment(0)
S
4

There is a lightweight JSON library for C# called SimpleJson.

It supports .NET 3.5+, Silverlight and Windows Phone 7.

It supports dynamic for .NET 4.0

It can also be installed as a NuGet package

Install-Package SimpleJson
Scud answered 29/5, 2011 at 19:39 Comment(2)
Yeah but how do you use it? Poorly answeredClaiborne
Hope this helps csharp.hotexamples.com/examples/-/SimpleJson/-/…Subminiaturize
R
4

Use DataSet(C#) with JavaScript. A simple function for creating a JSON stream with DataSet input. Create JSON content like (multi table dataset):

[[{a:1,b:2,c:3},{a:3,b:5,c:6}],[{a:23,b:45,c:35},{a:58,b:59,c:45}]]

Just client side, use eval. For example,

var d = eval('[[{a:1,b:2,c:3},{a:3,b:5,c:6}],[{a:23,b:45,c:35},{a:58,b:59,c:45}]]')

Then use:

d[0][0].a // out 1 from table 0 row 0

d[1][1].b // out 59 from table 1 row 1

// Created by Behnam Mohammadi And Saeed Ahmadian
public string jsonMini(DataSet ds)
{
    int t = 0, r = 0, c = 0;
    string stream = "[";

    for (t = 0; t < ds.Tables.Count; t++)
    {
        stream += "[";
        for (r = 0; r < ds.Tables[t].Rows.Count; r++)
        {
            stream += "{";
            for (c = 0; c < ds.Tables[t].Columns.Count; c++)
            {
                stream += ds.Tables[t].Columns[c].ToString() + ":'" +
                          ds.Tables[t].Rows[r][c].ToString() + "',";
            }
            if (c>0)
                stream = stream.Substring(0, stream.Length - 1);
            stream += "},";
        }
        if (r>0)
            stream = stream.Substring(0, stream.Length - 1);
        stream += "],";
    }
    if (t>0)
        stream = stream.Substring(0, stream.Length - 1);
    stream += "];";
    return stream;
}
Robtrobust answered 28/1, 2014 at 7:47 Comment(0)
J
4

To get an ExpandoObject:

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

Container container = JsonConvert.Deserialize<Container>(jsonAsString, new ExpandoObjectConverter());
Josie answered 4/3, 2014 at 5:18 Comment(0)
S
4

How to parse easy JSON content with dynamic & JavaScriptSerializer

Please add reference of System.Web.Extensions and add this namespace using System.Web.Script.Serialization; at top:

public static void EasyJson()
{
    var jsonText = @"{
        ""some_number"": 108.541,
        ""date_time"": ""2011-04-13T15:34:09Z"",
        ""serial_number"": ""SN1234""
    }";

    var jss = new JavaScriptSerializer();
    var dict = jss.Deserialize<dynamic>(jsonText);

    Console.WriteLine(dict["some_number"]);
    Console.ReadLine();
}

How to parse nested & complex json with dynamic & JavaScriptSerializer

Please add reference of System.Web.Extensions and add this namespace using System.Web.Script.Serialization; at top:

public static void ComplexJson()
{
    var jsonText = @"{
        ""some_number"": 108.541,
        ""date_time"": ""2011-04-13T15:34:09Z"",
        ""serial_number"": ""SN1234"",
        ""more_data"": {
            ""field1"": 1.0,
            ""field2"": ""hello""
        }
    }";

    var jss = new JavaScriptSerializer();
    var dict = jss.Deserialize<dynamic>(jsonText);

    Console.WriteLine(dict["some_number"]);
    Console.WriteLine(dict["more_data"]["field2"]);
    Console.ReadLine();
}
Sagittal answered 21/5, 2018 at 9:38 Comment(0)
T
4

I really like System.Web.Helpers,

dynamic data = Json.Decode(json);

as it supports usage like

var val = data.Members.NumberTen;

or

var val data.Members["10"];

The reference to System.Web.Helpers.DLL is really crazy, it is not even console and desktop app friendly. Here is my attempt to extract the same functionalities as a standalone file directly from https://github.com/mono/aspnetwebstack/tree/master/src/System.Web.Helpers (Share this as for education purpose only)

// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Dynamic;
using System.Linq.Expressions;
using System.Runtime.CompilerServices;
using Microsoft.CSharp.RuntimeBinder;
using System.Web.Script.Serialization;
using System.IO;
using System.Collections;
using System.Linq;
using System.Globalization;

namespace System.Web.Helpers
{
    public static class Json
    {
        private static readonly JavaScriptSerializer _serializer = CreateSerializer();

        public static string Encode(object value)
        {
            // Serialize our dynamic array type as an array
            DynamicJsonArray jsonArray = value as DynamicJsonArray;
            if (jsonArray != null)
            {
                return _serializer.Serialize((object[])jsonArray);
            }

            return _serializer.Serialize(value);
        }

        public static void Write(object value, TextWriter writer)
        {
            writer.Write(_serializer.Serialize(value));
        }

        public static dynamic Decode(string value)
        {
            return WrapObject(_serializer.DeserializeObject(value));
        }

        public static dynamic Decode(string value, Type targetType)
        {
            return WrapObject(_serializer.Deserialize(value, targetType));
        }

        public static T Decode<T>(string value)
        {
            return _serializer.Deserialize<T>(value);
        }

        private static JavaScriptSerializer CreateSerializer()
        {
            JavaScriptSerializer serializer = new JavaScriptSerializer();
            serializer.RegisterConverters(new[] { new DynamicJavaScriptConverter() });
            return serializer;
        }
        internal class DynamicJavaScriptConverter : JavaScriptConverter
        {
            public override IEnumerable<Type> SupportedTypes
            {
                get
                {
                    yield return typeof(IDynamicMetaObjectProvider);
                    yield return typeof(DynamicObject);
                }
            }

            public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
            {
                throw new NotSupportedException();
            }

            public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
            {
                Dictionary<string, object> dictionary = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
                IEnumerable<string> memberNames = DynamicHelper.GetMemberNames(obj);
                foreach (string item in memberNames)
                {
                    dictionary[item] = DynamicHelper.GetMemberValue(obj, item);
                }

                return dictionary;
            }
        }
        internal static dynamic WrapObject(object value)
        {
            // The JavaScriptSerializer returns IDictionary<string, object> for objects
            // and object[] for arrays, so we wrap those in different dynamic objects
            // so we can access the object graph using dynamic
            var dictionaryValues = value as IDictionary<string, object>;
            if (dictionaryValues != null)
            {
                return new DynamicJsonObject(dictionaryValues);
            }

            var arrayValues = value as object[];
            if (arrayValues != null)
            {
                return new DynamicJsonArray(arrayValues);
            }

            return value;
        }

    }
    // REVIEW: Consider implementing ICustomTypeDescriptor and IDictionary<string, object>
    public class DynamicJsonObject : DynamicObject
    {
        private readonly IDictionary<string, object> _values;

        public DynamicJsonObject(IDictionary<string, object> values)
        {
            Debug.Assert(values != null);
            _values = values.ToDictionary(p => p.Key, p => Json.WrapObject(p.Value),
                                          StringComparer.OrdinalIgnoreCase);
        }

        public override bool TryConvert(ConvertBinder binder, out object result)
        {
            result = null;
            if (binder.Type.IsAssignableFrom(_values.GetType()))
            {
                result = _values;
            }
            else
            {
                throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, "HelpersResources.Json_UnableToConvertType", binder.Type));
            }
            return true;
        }

        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            result = GetValue(binder.Name);
            return true;
        }

        public override bool TrySetMember(SetMemberBinder binder, object value)
        {
            _values[binder.Name] = Json.WrapObject(value);
            return true;
        }

        public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value)
        {
            string key = GetKey(indexes);
            if (!String.IsNullOrEmpty(key))
            {
                _values[key] = Json.WrapObject(value);
            }
            return true;
        }

        public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
        {
            string key = GetKey(indexes);
            result = null;
            if (!String.IsNullOrEmpty(key))
            {
                result = GetValue(key);
            }
            return true;
        }

        private static string GetKey(object[] indexes)
        {
            if (indexes.Length == 1)
            {
                return (string)indexes[0];
            }
            // REVIEW: Should this throw?
            return null;
        }

        public override IEnumerable<string> GetDynamicMemberNames()
        {
            return _values.Keys;
        }

        private object GetValue(string name)
        {
            object result;
            if (_values.TryGetValue(name, out result))
            {
                return result;
            }
            return null;
        }
    }
    [SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix", Justification = "This class isn't meant to be used directly")]
    public class DynamicJsonArray : DynamicObject, IEnumerable<object>
    {
        private readonly object[] _arrayValues;

        public DynamicJsonArray(object[] arrayValues)
        {
            Debug.Assert(arrayValues != null);
            _arrayValues = arrayValues.Select(Json.WrapObject).ToArray();
        }

        public int Length
        {
            get { return _arrayValues.Length; }
        }

        public dynamic this[int index]
        {
            get { return _arrayValues[index]; }
            set { _arrayValues[index] = Json.WrapObject(value); }
        }

        public override bool TryConvert(ConvertBinder binder, out object result)
        {
            if (_arrayValues.GetType().IsAssignableFrom(binder.Type))
            {
                result = _arrayValues;
                return true;
            }
            return base.TryConvert(binder, out result);
        }

        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            // Testing for members should never throw. This is important when dealing with
            // services that return different json results. Testing for a member shouldn't throw,
            // it should just return null (or undefined)
            result = null;
            return true;
        }

        public IEnumerator GetEnumerator()
        {
            return _arrayValues.GetEnumerator();
        }

        private IEnumerable<object> GetEnumerable()
        {
            return _arrayValues.AsEnumerable();
        }

        IEnumerator<object> IEnumerable<object>.GetEnumerator()
        {
            return GetEnumerable().GetEnumerator();
        }

        [SuppressMessage("Microsoft.Usage", "CA2225:OperatorOverloadsHaveNamedAlternates", Justification = "This class isn't meant to be used directly")]
        public static implicit operator object[](DynamicJsonArray obj)
        {
            return obj._arrayValues;
        }

        [SuppressMessage("Microsoft.Usage", "CA2225:OperatorOverloadsHaveNamedAlternates", Justification = "This class isn't meant to be used directly")]
        public static implicit operator Array(DynamicJsonArray obj)
        {
            return obj._arrayValues;
        }
    }

    /// <summary>
    /// Helper to evaluate different method on dynamic objects
    /// </summary>
    public static class DynamicHelper
    {
        // We must pass in "object" instead of "dynamic" for the target dynamic object because if we use dynamic, the compiler will
        // convert the call to this helper into a dynamic expression, even though we don't need it to be.  Since this class is internal,
        // it cannot be accessed from a dynamic expression and thus we get errors.

        // Dev10 Bug 914027 - Changed the first parameter from dynamic to object, see comment at top for details
        public static bool TryGetMemberValue(object obj, string memberName, out object result)
        {
            try
            {
                result = GetMemberValue(obj, memberName);
                return true;
            }
            catch (RuntimeBinderException)
            {
            }
            catch (RuntimeBinderInternalCompilerException)
            {
            }

            // We catch the C# specific runtime binder exceptions since we're using the C# binder in this case
            result = null;
            return false;
        }

        // Dev10 Bug 914027 - Changed the first parameter from dynamic to object, see comment at top for details
        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "We want to swallow exceptions that happen during runtime binding")]
        public static bool TryGetMemberValue(object obj, GetMemberBinder binder, out object result)
        {
            try
            {
                // VB us an instance of GetBinderAdapter that does not implement FallbackGetMemeber. This causes lookup of property expressions on dynamic objects to fail.
                // Since all types are private to the assembly, we assume that as long as they belong to CSharp runtime, it is the right one. 
                if (typeof(Binder).Assembly.Equals(binder.GetType().Assembly))
                {
                    // Only use the binder if its a C# binder.
                    result = GetMemberValue(obj, binder);
                }
                else
                {
                    result = GetMemberValue(obj, binder.Name);
                }
                return true;
            }
            catch
            {
                result = null;
                return false;
            }
        }

        // Dev10 Bug 914027 - Changed the first parameter from dynamic to object, see comment at top for details
        public static object GetMemberValue(object obj, string memberName)
        {
            var callSite = GetMemberAccessCallSite(memberName);
            return callSite.Target(callSite, obj);
        }

        // Dev10 Bug 914027 - Changed the first parameter from dynamic to object, see comment at top for details
        public static object GetMemberValue(object obj, GetMemberBinder binder)
        {
            var callSite = GetMemberAccessCallSite(binder);
            return callSite.Target(callSite, obj);
        }

        // dynamic d = new object();
        // object s = d.Name;
        // The following code gets generated for this expression:
        // callSite = CallSite<Func<CallSite, object, object>>.Create(Binder.GetMember(CSharpBinderFlags.None, "Name", typeof(Program), new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) }));
        // callSite.Target(callSite, d);
        // typeof(Program) is the containing type of the dynamic operation.
        // Dev10 Bug 914027 - Changed the callsite's target parameter from dynamic to object, see comment at top for details
        public static CallSite<Func<CallSite, object, object>> GetMemberAccessCallSite(string memberName)
        {
            var binder = Binder.GetMember(CSharpBinderFlags.None, memberName, typeof(DynamicHelper), new[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) });
            return GetMemberAccessCallSite(binder);
        }

        // Dev10 Bug 914027 - Changed the callsite's target parameter from dynamic to object, see comment at top for details
        public static CallSite<Func<CallSite, object, object>> GetMemberAccessCallSite(CallSiteBinder binder)
        {
            return CallSite<Func<CallSite, object, object>>.Create(binder);
        }

        // Dev10 Bug 914027 - Changed the first parameter from dynamic to object, see comment at top for details
        public static IEnumerable<string> GetMemberNames(object obj)
        {
            var provider = obj as IDynamicMetaObjectProvider;
            Debug.Assert(provider != null, "obj doesn't implement IDynamicMetaObjectProvider");

            Expression parameter = Expression.Parameter(typeof(object));
            return provider.GetMetaObject(parameter).GetDynamicMemberNames();
        }
    }

}
Tideway answered 4/8, 2022 at 3:45 Comment(0)
R
3

With Cinchoo ETL - an open source library available to parse JSON into a dynamic object:

string json = @"{
    ""key1"": [
        {
            ""action"": ""open"",
            ""timestamp"": ""2018-09-05 20:46:00"",
            ""url"": null,
            ""ip"": ""66.102.6.98""
        }
    ]
}";
using (var p = ChoJSONReader.LoadText(json)
    .WithJSONPath("$..key1")
    )
{
    foreach (var rec in p)
    {
        Console.WriteLine("Action: " + rec.action);
        Console.WriteLine("Timestamp: " + rec.timestamp);
        Console.WriteLine("URL: " + rec.url);
        Console.WriteLine("IP address: " + rec.ip);
    }
}

Output:

Action: open
Timestamp: 2018-09-05 20:46:00
URL: http://www.google.com
IP address: 66.102.6.98

Sample fiddle: https://dotnetfiddle.net/S0ehSV

For more information, please visit codeproject articles

Disclaimer: I'm the author of this library.

Rubiaceous answered 7/9, 2018 at 1:42 Comment(0)
S
2

try this way!

JSON example:

[{
    "id": 140,
    "group": 1,
    "text": "xxx",
    "creation_date": 123456,
    "created_by": "[email protected]",
    "tags": ["xxxxx"]
  }, {
    "id": 141,
    "group": 1,
    "text": "xxxx",
    "creation_date": 123456,
    "created_by": "[email protected]",
    "tags": ["xxxxx"]
}]

C# code:

var jsonString = (File.ReadAllText(Path.Combine(Directory.GetCurrentDirectory(),"delete_result.json")));
var objects = JsonConvert.DeserializeObject<dynamic>(jsonString);
foreach(var o in objects)
{
    Console.WriteLine($"{o.id.ToString()}");
}
Stopcock answered 17/6, 2019 at 9:33 Comment(0)
N
0

what i needed was to return a json model with varying fields. My model is like this but it can change.

{
    "employees":
    [
        { "name": "Darth", "surname": "Vader", "age": "27", "department": "finance"},
        { "name": "Luke", "surname": "Skywalker", "age": "25", "department": "IT"},
        { "name": "Han", "surname": "Solo", "age": "26", "department": "credit"}
    ]
}

To get a list of data values

    JObject array = JObject.Parse(model.JsonData);
    var tableData = new List<JsonDynamicModel>();

    foreach (var objx in array.Descendants().OfType<JProperty>().Where(p => p.Value.Type != JTokenType.Array && p.Value.Type != JTokenType.Object))
            {
                var name = ((JValue)objx.Name).Value;
                var value = ((JValue)objx.Value).Value;
                if (tableData.FirstOrDefault(x => x.ColumnName == name.ToString()) == null)
                {
                    tableData.Add(new JsonDynamicModel
                    {
                        ColumnName = name.ToString(),
                        Values = new List<string> { value.ToString() },
                    });
                }
                else
                {
                    tableData.FirstOrDefault(x=>x.ColumnName == name.ToString()).Values.Add(value.ToString());
                }
            }

The output will be as follows. Then I converted the resulting model into an html table, I used this method to create an html table

// output
tableData[0].ColumnName -> "name";
tableData[0].Values -> {"Darth", "Luke", "Han" }
tableData[1].ColumnName -> "surname";
tableData[1].Values -> {"Vader", "Skywalker", "Solo" }
...
Nashoma answered 27/6, 2022 at 10:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.