Search code examples
wcf.net-4.0dictionaryknown-types

wcf .net4 dictionary containing dictionaries


I am trying to return an array of dictionary <string, object> where the object may contain a basic type such as int, bool, etc or it could contain another array of dictionary<string, object>

Though I can get it serialize fine, it will not deserialize if there is a dictionary within the dictionary.

I get the following error:

Error in line 1 position 543. Element 'http://schemas.microsoft.com/2003/10/Serialization/Arrays:Value' contains data from a type that maps to the name 'http://schemas.microsoft.com/2003/10/Serialization/Arrays:ArrayOfArrayOfKeyValueOfstringanyType'. The deserializer has no knowledge of any type that maps to this name. Consider using a DataContractResolver or add the type corresponding to 'ArrayOfArrayOfKeyValueOfstringanyType' to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding it to the list of known types passed to DataContractSerializer.

the class:

[DataContract(Namespace = "CISICPD")]
[KnownType(typeof(Dictionary<string,object>))]
public class TestResponse
{
    [DataMember]
    public Dictionary<string,object>[] Results;
}

function:

public TestResponse test(string test1, string test2)
    {
        TestResponse r = new TestResponse();
        r.Results = new Dictionary<string, object>[1];
        r.Results[0] = new Dictionary<string, object>();
        r.Results[0].Add("field1", 26);
        Dictionary<string, object>[] d = new Dictionary<string, object>[1];
        d[0] = new Dictionary<string, object>();
        d[0].Add("inner", 28);
        r.Results[0].Add("dictionary", d);
        return r;
    }

running this gives the error message but i think ive got the correct knowntype?

CISICPD.CPDClient t = new CISICPD.CPDClient();
CISICPD.TestResponse response = t.test("dgdf", "dfsdfd");

Solution

  • You simply need to add the following property to your datacontract class.

    [DataMember]
    public object UsedForKnownTypeSerializationObject;
    

    So now the generated proxy contains the Knowtypes you set on the datacontract. I had the same problem and this is the only solution I came up with. If you don't at the a property of type Object to you DataContract class, the generated proxy doesn't contain the declared knowtypes

    For example:

    [DataContract]
    [KnownType(typeof(List<String>))]
    public class Foo
    {
        [DataMember]
        public String FooName { get; set; }
    
        [DataMember]
        public IDictionary<String, Object> Inputs { get; set; }
    
        [DataMember]
        private Object UsedForKnownTypeSerializationObject{ get; set; }
    
    }
    

    It's not as pretty because you end up with a dummy property which doesn't have any functional implementation. But then again I don't have another solution.