0

I have a little test class like so :

public class Command
{
    public dynamic MyData { get; set; }
}

As the dynamic MyData I want to use ExpandoObject, so I can do:

Command cmd = new Command();
cmd.MyData = new ExpandoObject();
cmd.MyData.SomeStuff = 4;
cmd.MyData.SomeOtherStuff = "hi";

I am trying to serialize to/deserialize from json. To do this I am using JavaScriptSerializer.
I want an example object above to serialize to:

{
    MyData : {
        SomeStuff : 4,
        SomeOtherStuff : "hi"
    }
}

To do this I need a JavaScriptConverter (taken from this website):

public class ExpandoJsonConverter : JavaScriptConverter
{
    public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
    {
        return dictionary.ToExpando();
    }

    public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
    {
        var result = new Dictionary<string, object>();
        var dictionary = obj as IDictionary<string, object>;
        foreach (var item in dictionary)
            result.Add(item.Key, item.Value);
        return result;
    }

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

public static class IDictionaryExtensions {
    /// <summary>
    /// Extension method that turns a dictionary of string and object to an ExpandoObject
    /// Snagged from http://theburningmonk.com/2011/05/idictionarystring-object-to-expandoobject-extension-method/
    /// </summary>
    public static ExpandoObject ToExpando(this IDictionary<string, object> dictionary) {
        var expando = new ExpandoObject();
        var expandoDic = (IDictionary<string, object>)expando;

        // go through the items in the dictionary and copy over the key value pairs)
        foreach (var kvp in dictionary) {
            // if the value can also be turned into an ExpandoObject, then do it!
            if (kvp.Value is IDictionary<string, object>) {
                var expandoValue = ((IDictionary<string, object>)kvp.Value).ToExpando();
                expandoDic.Add(kvp.Key, expandoValue);
            }
            else if (kvp.Value is ICollection) {
                // iterate through the collection and convert any strin-object dictionaries
                // along the way into expando objects
                var itemList = new List<object>();
                foreach (var item in (ICollection)kvp.Value) {
                    if (item is IDictionary<string, object>) {
                        var expandoItem = ((IDictionary<string, object>)item).ToExpando();
                        itemList.Add(expandoItem);
                    }
                    else {
                        itemList.Add(item);
                    }
                }

                expandoDic.Add(kvp.Key, itemList);
            }
            else {
                expandoDic.Add(kvp);
            }
        }

        return expando;
    }
}

Now this works neat for serializing, but there is a following problem with deserializing:

  • since MyData is a dynamic object, and the ExpandoJsonConverter expects ExpandoObject, the data deserialized to MyData is of type IDictionary<string, object>.
  • if I change dynamic MyData to be ExpandoObject MyData, I won't be able to say cmd.MyData.SomeStuff = 4;, the compiler will tell me that "ExpandoObject does not have property named SomeStuff".
  • finally, I could add dynamic to the list of supported types of ExpandoJsonConverter, byt wait, you cant do typeof(dynamic).

Is anyone aware of a neat workaround? I would really like this functionality, but I can't use 3rd party serialization libraries like Newtonsoft. Thanks.

Stephen Kennedy
  • 20,585
  • 22
  • 95
  • 108
Daniel Gruszczyk
  • 5,379
  • 8
  • 47
  • 86
  • Would http://stackoverflow.com/a/5157855 satisfy your requirement? – Bernhard Hofmann Mar 11 '14 at 15:36
  • Thanks for the reply. Again - the whole topic is about serializing to JSON, which I have achieved. My problem is going the other way (deserializing JSON), which gives me back dictionary instead of ExpandoObject. – Daniel Gruszczyk Mar 11 '14 at 15:44

1 Answers1

0

Deserialize to ExpandoObject but declare the variable dynamic, i.e. what you need is dynamic d = js.Deserialize<ExpandoObject>(json):

string json = @"{
    MyData : {
        SomeStuff : 4,
        SomeOtherStuff : ""hi""
    }
}";

var js = new JavaScriptSerializer();
js.RegisterConverters(new[] { new ExpandoJsonConverter() });    
dynamic d = js.Deserialize<ExpandoObject>(json);    
Console.WriteLine(d.MyData.SomeOtherStuff);

Output:

hi

If you need a Command object, just construct one manually and inject the dynamic object returned from the serializer:

var cmd = new Command { MyData = d };
Console.WriteLine(cmd.MyData.SomeStuff);
Stephen Kennedy
  • 20,585
  • 22
  • 95
  • 108