views:

147

answers:

3

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

A: 

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.

Daniel Earwicker
+3  A: 

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.

Reed Copsey
Surely there is an implementation using only the built in datacontractjsonserializer. It'd be great to avoid a third party assembly reference
Joel Martinez
Unfortunately that library doesn't work with .NET 4 RTM.
Drew Noakes
+2  A: 

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:

public class DynamicJsonObject : DynamicObject
{
    private IDictionary<string, object> Dictionary { get; set; }

    public DynamicJsonObject(IDictionary<string, object> dictionary)
    {
        Dictionary = dictionary;
    }

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        if (!Dictionary.TryGetValue(binder.Name, out result))
            return false;

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

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

        return true;
    }
}

public 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) })); }
    }
}

You can use it like this:

string json = ...;

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

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

I'm interested in any discussion about this approach.

Drew Noakes