Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't WCF pass an object in a dictionary?

Tags:

c#

.net

wcf

In my WCF service I have the object QualifiedNumber defined as KnownType and ServiceKnown type. If I used the QualifiedNumber in the following methods:

This one does NOT work. It throws an exception that in part reads:

Element 'http://schemas.microsoft.com/2003/10/Serialization/Arrays:Value' contains data of the 'http://schemas.datacontract.org/2004/07 ServiceLibrary.Web.Model:QualifiedNumber' data contract. The deserializer has no knowledge of any type that maps to this contract. cannot deserialize because the definition of QualifiedNumber is not known.

[OperationContract]
public Dictionary<int, object> TestDictionaryGet()
{
    Dictionary<int, object> retDict = new Dictionary<int, object>();

    retDict.Add(1, new QualifiedNumber(new decimal(1.2), "<"));
    retDict.Add(2, "pass a simple string");

    return retDict;
}

This one DOES work

public struct element
{
    public int key;
    public object value;
}

[OperationContract]
public List<element> TestElementListGet()
{
    Dictionary<int, object> retDict = new Dictionary<int, object>();

    retDict.Add(1, new QualifiedNumber(new decimal(1.2), "<"));
    retDict.Add(2, "pass a simple string");

    List<element> retElements = new List<element>();
    foreach (KeyValuePair<int, object> item in retDict)
    {
        element newElement;
        newElement.key = item.Key;
        newElement.value = item.Value;

        retElements.Add(newElement);
    }

    return retElements;
}

What is it about the dictionary that causes the exception?

like image 600
JerryKur Avatar asked May 10 '11 17:05

JerryKur


2 Answers

Here is a detailed article on generic dictionary serialization over WCF:

http://www.request-response.com/blog/PermaLink,guid,ff5fab81-affb-4b2b-aa67-c80bdfc86cbd.aspx

The takeaway quote from that article would be:

There is no way to meaningfully convey the semantics of a .NET dictionary class using WSDL/XSD.

like image 103
Dave Swersky Avatar answered Oct 04 '22 05:10

Dave Swersky


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.

like image 42
wkalter Avatar answered Oct 04 '22 05:10

wkalter