JSON.net and WCF deserialization

Jan 19, 2010 at 7:38 AM

Hi,

I found a problem in the built-in WCF JSON serializer, where it does not (de)serialize dictionaries as expected. This is known (see under the heading "Collections, Dictionaries and Arrays" in http://msdn.microsoft.com/en-us/library/bb412170.aspx) but I quite frankly do not think it is the right design decision. Since we still would like to use WCF, my question is, if any of you have any experience in replacing the built-in WCF JSON serializer with JSON.net?

Kind regards

Morten Boysen

Aug 18, 2010 at 1:57 AM
Did you ever figure this out?
Sep 10, 2010 at 6:20 PM

Give RestCake (http://restcake.net) a look.  You can use RestCake for your REST services instead of WCF.  The transition is painless, as RestCake uses all of the existing WCF attributes in your service classes.  It uses Json.NET as the default serializer.

Disclaimer: I'm the author of the RestCake library.

Sep 11, 2010 at 9:20 PM
Edited Sep 11, 2010 at 9:28 PM

Hi,

 

No, I never found a solution other than he on presented in the link: Create a custom type to wrap a Dictionary<,>.

 

I also filed this bug report: https://connect.microsoft.com/wcf/feedback/details/525127/json-deserializer-does-not-deserialize-a-dictionary-correctly?wa=wsignin1.0

 

Next time I am doing REST, it might very be with ASP.NET MVC, OData or some completely different library (like RestCake - nice project BTW!) that WCF, even though it has gotten better with WCF 4.

 

Cheers,

Morten Boysen

Jun 9, 2011 at 5:42 PM
Edited Jun 9, 2011 at 5:45 PM

You can write the JsonContract for that purpose to tell the JSON.NET how to parse array-like WCF dictionary representation.

You can use following code to deserialize types, which has the properties of type Dictionary<TKey, TValue> from WCF JSON:

 ReturnType result = JsonConvert.DeserializeObject<ReturnType>(strJson, new WcfDictionaryConverter());

// Wcf Dictionary converter
public class WcfDictionaryConverter : JsonConverter
    {
        /// <summary>
        /// Writes the JSON representation of the object.
        /// </summary>
        /// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
        /// <param name="value">The value.</param>
        /// <param name="serializer">The calling serializer.</param>
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            serializer.Serialize(writer, value);
        }
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            IList<Type> genericArguments = objectType.GetGenericArguments();
            Type keyType = genericArguments[0];
            Type valueType = genericArguments[1];

            Dictionary<object, object> dict = new Dictionary<object, object>();

            if (reader.TokenType == JsonToken.StartArray)
            {
                reader.Read();
                while (reader.TokenType == JsonToken.StartObject)
                {
                    reader.Read();  // "Key" property name

                    while (reader.TokenType == JsonToken.PropertyName)
                    {
                        reader.Read();
                        object key = serializer.Deserialize(reader, keyType);
                        // read "Value" property name
                        reader.Read();
                        reader.Read();
                        object value = serializer.Deserialize(reader, valueType);

                        dict.Add(key, value);

                        reader.Read(); // deserialized object
                    }

                    reader.Read();  // key value pair
                }
            }

            System.Collections.IDictionary genericDict = (System.Collections.IDictionary)Activator.CreateInstance(objectType);
            foreach (var pair in dict)
            {
                genericDict.Add(pair.Key, pair.Value);
            }

            return genericDict;
        }

        public override bool CanConvert(Type objectType)
        {

            if (objectType.IsGenericType)
                return (objectType.GetGenericTypeDefinition() == typeof(Dictionary<,>));

            return false;
        }
    }