Deserialize JSON into C# dynamic object?

Unfortunately the blog post by Nikhil Kothari doesn't work with . NET 4 RTM.

Unfortunately the blog post by Nikhil Kothari doesn't work with . NET 4 RTM. 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: 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; private sealed class DynamicJsonConverter : JavaScriptConverter { public override object Deserialize(IDictionary dictionary, Type type, JavaScriptSerializer serializer) { if (dictionary == null) throw new ArgumentNullException("dictionary"); return type == typeof(object)?

New DynamicJsonObject(dictionary) : null; } public override IDictionary Serialize(object obj, JavaScriptSerializer serializer) { throw new NotImplementedException(); } public override IEnumerable SupportedTypes { get { return new ReadOnlyCollection(new List(new { typeof(object) })); } } #region Nested type: DynamicJsonObject private sealed class DynamicJsonObject : DynamicObject { private readonly IDictionary _dictionary; public DynamicJsonObject(IDictionary 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) { new DynamicJsonObject((IDictionary)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) new DynamicJsonObject((IDictionary)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; } var dictionary = result as IDictionary; if (dictionary! = null) { result = new DynamicJsonObject(dictionary); return true; } var arrayList = result as ArrayList; if (arrayList! = null && arrayList.

Count > 0) { if (arrayList0 is IDictionary) result = new List(arrayList.Cast(). Select(x => new DynamicJsonObject(x))); else result = new List(arrayList.Cast()); } return true; } } #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: var data = serializer. Deserialize(json, typeof(object)); data. Date; // "21/11/2010" data.Items.

Count; // 2 data. Items0.Name; // "Apple" data. Items0.

Price; // 12.3 (as a decimal) data. Items1. Name; // "Grape" data.

Items1. Price; // 3.21 (as a decimal) I'm interested in any discussion about this approach. EDIT I updated the code to fix a small bug (with lists of complex types) and to include a ToString method that outputs the JSON string, which I found useful for debugging.

You can drop the two methods out if you don't want them as they aren't required for deserialisation.

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 :) – Mark Dickinson Feb 9 '11 at 13:05 @Mark, it's been a while since I looked at this but from memory what you're describing sounds right. – Drew Noakes Feb 9 '11 at 14:01 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?

– Stewie Griffin Jun 18 '11 at 20:17 @Stewie, the type I'm using is System.Web.Script.Serialization. JavaScriptSerializer which is in version 4.0.0.0 of System.Web.dll. – Drew Noakes Jun 19 '11 at 8:36 System.Web.Script.Serialization.

JavaScriptSerializer is in System.Web.Extensions. Dll - goo. Gl/8zRrj – rushonerok Dec 12 '11 at 16:43.

. Net 4.0 has a built-in library to do this: using System.Web.Script. Serialization; JavaScriptSerializer jss = new JavaScriptSerializer(); var d=jss.

Deserialize(str); This is the simplest way.

Most of the previous answers came before . NET 4.0 RTM. – jswanson Jun 13 '11 at 14:08 3 have you tried this?

It returns Dictionary. Unless I'm missing something, your example does not return a dynamic object. – sergiopereira Jun 13 '11 at 15:15 3 This doesn't work, it just return a dict in the form of a dynamic – mattmanser Jun 30 '11 at 15:56 11 @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.

– mattmanser Jul 1 '11 at 9:22 3 @mattmanser...I already wasted those minutes trying his code cus I didn't read the comments or scrolled down :( – Lol coder Jul 13 '11 at 15:05.

JsonFx can deserialize json into dynamic objects. Https://github.com/jsonfx/jsonfx.

1 That's exactly what I was looking for last year. Thanks! – jswanson Mar 2 '11 at 19:00 1 Works perfectly, to dynamic/expando objects.

– Bryan Bailliache Oct 27 '11 at 18:22.

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 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 dictionary) { var result = new ExpandoObject(); var dic = result as IDictionary; foreach (var item in dictionary) { var valueAsDic = item. Value as IDictionary; 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; 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 Serialize(object obj, JavaScriptSerializer serializer) { throw new NotImplementedException(); } public override IEnumerable SupportedTypes { get { return new ReadOnlyCollection(new List(new { typeof(object) })); } } } }.

Nikhil Kothari blogged about doing this. He included a link to his library which provides a dynamic implementation of a REST client, which works on JSON data. He also has a JSON client that works off strings of JSON data directly.

1 Surely there is an implementation using only the built in datacontractjsonserializer. It'd be great to avoid a third party assembly reference – Joel Martinez Sep 21 '10 at 13:05 Unfortunately that library doesn't work with . NET 4 RTM.

– Drew Noakes Sep 27 '10 at 12:56.

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.

Its probably a little late to help you but 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.

There is a lightweight json library for C# called SimpleJson which can be found at simplejson.codeplex.com It supports .net" rel="nofollow">.net 3.5+, silverlight and windows phone 7. Supports dynamic for .net" rel="nofollow">.net 4.0 Can also be installed as a nuget package Install-Package SimpleJson.

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>(value); return GetExpando(dictionary); } private static ExpandoObject GetExpando(IDictionary dictionary) { var expando = (IDictionary)new ExpandoObject(); foreach (var item in dictionary) { var innerDictionary = item. Value as IDictionary; 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.

I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.

Related Questions