Deserialize JSON into C# dynamic object?
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);
jswanson
Updated on December 23, 2021Comments
-
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 almost 14 yearsIf 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 almost 14 yearsI'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 almost 14 yearsI'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 over 13 yearsUnfortunately 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 over 5 yearsUpdate October 2018, this is how the magic happens: stackoverflow.com/a/48023576/4180382
-
-
Mark Dickinson over 13 yearsThanks 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 over 13 years@Mark, it's been a while since I looked at this but from memory what you're describing sounds right.
-
jswanson about 13 yearsMost of the previous answers came before .NET 4.0 RTM.
-
mitaka about 13 yearshave you tried this? It returns
Dictionary<string,object>
. Unless I'm missing something, your example does not return a dynamic object. -
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 about 13 yearsI 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 about 13 years@Stewie, the type I'm using is
System.Web.Script.Serialization.JavaScriptSerializer
which is in version 4.0.0.0 ofSystem.Web.dll
. -
mattmanser almost 13 yearsThis doesn't work, it just return a dict in the form of a dynamic
-
Peter Long almost 13 years@mattmanser, please learn what is dynamic. every dynamic type would be resolved to a static type finally.
-
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 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 almost 13 years@mattmanser, instead of
d["code"].Value
, you wantd.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 over 12 yearsSystem.Web.Script.Serialization.JavaScriptSerializer is in System.Web.Extensions.dll - goo.gl/8zRrj
-
Quantumplation over 12 yearsI 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 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 over 12 yearsYes, 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 over 12 yearsYou 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 about 12 yearsFYI 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 over 11 yearssometimes 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 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 over 11 yearsYou will find this assembly in the Extensions group under Assemblies in Visual Studio 2012
-
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 toTryGetMember
you can overrideTryGetIndex
, which gives you exactly the same behavior as in JS. Then you can doobj["params"]
orobj["background-color"]
for awkward field names. -
cikatomo over 11 yearsId don't get it. This is by far most simple solution and nobody mentions it.
-
Usama Khalil about 11 yearsAny Issues with using dynamic ? How can we handle exceptions efficiently if input JSON does not contain the properties..
-
Mike about 11 yearsIf you're wanting to strongly type the model then be sure to use the Json.Decode<T>(string) method.
-
İbrahim Özbölük almost 11 yearsyes it's simple :) sometime you need serialize but don't want to include 3rd part dll
-
Royi Namir almost 11 yearsCan you elaborate on : how dynamic can access the DEserialized object via :
myObject["myprop"]
? I know it's done on runtime but how accessing it viamyObject["myprop"]
is valid ? -
İbrahim Özbölük almost 11 yearsYou 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 over 10 yearsthis 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 over 10 yearsInteresting, 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 about 10 yearsHow can you introspect the dynamic
stuff
? -
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 almost 10 yearsTo add this library to your project: stackoverflow.com/questions/8037895/…
-
cja over 9 yearsWhat'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 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 ofdynamic
allows code such asd.code
to be used. It's kind of pointless to cast a dictionary to a dynamic. -
Lee Louviere over 9 years@TomPeplow Tried this. It didn't work for me. It says that "JObject doesn't implement 'Name'".
-
nawfal about 9 yearsI 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 about 9 years@cja no difference: stackoverflow.com/questions/23645034/…
-
codeConcussion over 8 yearsI 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 methodasync
and I can't get adynamic
, I just get anobject
. Explicit casting does nothing, still just gives me anobject
. Is anyone else experiencing this? -
Illuminati about 8 yearsbut 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 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 over 7 yearsSystem.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 over 6 yearsFYI If you're using .NET Core, they moved this thing into the "microsoft-web-helpers" package.
-
LanchPad almost 6 yearsThe 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/types/… docs.microsoft.com/en-us/dotnet/csharp/programming-guide/types/…
-
StilgarISCA almost 6 yearsTo use the System.Web.Script.Serialization namespace your project needs a reference to System.Web.Extensions.
-
syonip over 5 yearsto use System.Web.Helpers you need to add a nuget package: nuget.org/packages/microsoft-web-helpers
-
davidthegrey over 5 yearsI 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 almost 5 yearsIf you can't make it work, try this:
dynamic v = JsonConvert.DeserializeObject<ExpandoObject>(someJSONstring);
-
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 over 4 yearsThis 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 over 4 yearsIn 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 over 4 yearsthis saved me a lot of time ! should be chosen as best answer !
-
zolty13 about 4 yearsnuget.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 almost 4 yearsbest solution on this page.
-
Pang over 3 yearsLast link in answer is dead - "403 Site Disabled | This site is stopped".
-
Fandango68 over 3 yearsYeah but how do you use it? Poorly answered
-
vt100 over 3 years
data.Items.Count
didn't work for me -data.Items.Length
did. -
RainCast about 3 yearsvisual studio didn't recognize Json class even after added using System.Web.Helpers;
-
singhswat about 3 yearsAn example will help wider audience
-
znn about 3 yearsMy favourite method so far
-
Shahroozevsky almost 3 yearsdude, +1 hug for you :D
-
stuzor almost 3 yearsI think the VS debugger Watch window fails to retrieve properties when called inside an async method. Works fine from a non-async method
-
Vidar over 2 yearsI don't understand why this answer is above the one with over 700 upvotes and marked as correct answer!?
-
Daniel Earwicker over 2 years@Vidar are you sorting by Oldest instead of by Votes?
-
Techiemanu over 2 yearsHope this helps csharp.hotexamples.com/examples/-/SimpleJson/-/…
-
Anirudha Gupta over 2 yearsIt's not working in .net 6, Any idea?. I want to read property which have array of elements.
-
Tengiz over 2 yearsIt 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.