Deserializing a dictionary that was serialized with DataContractJsonSerializer

May 18, 2011 at 2:16 PM

I ran into a problem recently which I was able to solve but was wondering if there was an easier way

  1. Have you solved this problem some other way?
  2. Recommendations for better solutions?

The Problem:

I have a WCF REST service that returns JSON using the default DataContractJsonSerializer. One of the clients to this REST API is a .NET silverlight which uses JSON.NET to serialize/deserialize messages to/from the API. This all works great EXCEPT for Dictionary<Tkey, TValue> objects. DataContractJsonSerializer and JSON.NET serialize these objects differently to JSON and thus do not work together.

http://stackoverflow.com/questions/4199321/how-to-deserialize-a-dictionary-using-datacontractjsonserializer

I am not an expert in either serializer, so i spent several hours trying to figure out the best way to solve this problem. Ultimately I created a JSON.NET "DictionaryConverter" which worked. I only needed it in one direction (reading JSON from the API). 

My solution:

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            var genericArguments = objectType.GetGenericArguments();
            var keyType = genericArguments[0];
            var valType = genericArguments[1];
            var dictionaryType = typeof(Dictionary<,>).MakeGenericType(genericArguments);
            var keyValueType = typeof(KeyValuePair<,>).MakeGenericType(genericArguments);
            var dictionary = (object)null;

            dictionary = Activator.CreateInstance(dictionaryType);
            reader.Read(); // StartArray

            while (reader.TokenType == JsonToken.StartObject)
            {
                var keyvaluepair = serializer.Deserialize(reader);
                var key = (JValue)((JContainer)keyvaluepair)["Key"];
                var val = (JValue)((JContainer)keyvaluepair)["Value"];
                dictionaryType.GetMethod("Add").Invoke(dictionary, new object[] { 
                    Convert.ChangeType(key.Value, keyType, null), 
                    Convert.ChangeType(val.Value, valType, null)
                });

                reader.Read();
            }

            return dictionary;
        }

        public override bool CanConvert(Type objectType)
        {
            if (!objectType.IsValueType && objectType.IsGenericType)
                return (objectType.GetGenericTypeDefinition() == typeof(Dictionary<,>));

            return false;
        }

Thanks!