Question

Suppose we start from scratch in Visual Studio 2010 and add a 'WCF Service Aplication'. We add this method and implementation:

// (in IService1.cs)
    [OperationContract]
    Dictionary<string, string> GetDictionary();

// (in Service1.svc.cs)
    public Dictionary<string, string> GetDictionary()
    {
        return new Dictionary<string, string>(
            StringComparer.InvariantCultureIgnoreCase);
    }

Then we add a new 'Console Application' to the same solution, add a Service Reference to our service project (using all the default settings), and add this code to Main:

        var c = new ServiceReference1.Service1Client();

        var d = c.GetDictionary();

        d.Add("key",string.Empty);
        // Since this *should* be a case-insensitive dictionary,
        // this add *should* fail
        d.Add("KEY", string.Empty);

        Console.WriteLine("Both Add()s succeeded :(");
        Console.ReadKey();

We expect this code to fall over, because a case-insensitive dictionary would regard key and KEY as the same key, and so would throw on the second Add.

Unfortunately, when everything is compiled and run, we get a sad face :(, because when the Dictionary comes across the WCF layer it 'forgets' that it was made with a specific, non-default, Comparer, and instead acquires strings default equality comparer.

Is there an easy setting to change so that the Comparer property of the Dictionary will be preserved as it goes across the wire? Or must I create a custom class?

(I've seen XML serialization of a Dictionary with a custom IEqualityComparer but it didn't offer me much enlightenment. I've also seen this codeproject comment from 3 years ago, but it is my question, not an answer)

Was it helpful?

Solution

If you use the standard mechanism like "Add Service Reference" etc., WCF by design will create a completely separate copy of your data structures based on the structure on the wire, e.g. the XML-serialized structure that can be expressed in XML schema (XSD).

This does not include anything that's more behavior (code) rather than actual data - things like comparers etc.

There is no setting to "turn" this on - it just cannot be done. The only way to solve this - when you control both ends of the communication wire, and both are .NET platforms - is to share that common stuff both sides need (service contracts, data contracts etc.) in a separate assembly that both the server as well as the client reference. On the client, you need to make sure to add the reference to that shared assembly before creating the WCF proxy - in that case, the WCF runtime will reuse the existing data structures (like your dictionary with a custom comparer) from the shared assembly, instead of creating new, boiler-plate copies.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top