本文介绍了如何使WCF序列化在通用字典上保留非默认Comparer?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我们从Visual Studio 2010开始,并添加一个WCF服务应用程序。我们添加这种方法和实现:

  //(在IService1.cs中)
[OperationContract]
字典< string,string> GetDictionary();

//(在Service1.svc.cs中)
public Dictionary< string,string> GetDictionary()
{
返回新字典< string,string>(
StringComparer.InvariantCultureIgnoreCase);
}

然后我们在同一个解决方案中添加一个新的控制台应用程序,添加一个服务参考我们的服务项目(使用所有默认设置),并将此代码添加到主:

  var c = new ServiceReference1.Service1Client(); 

var d = c.GetDictionary();

d.Add(key,string.Empty);
//由于这个*应该是一个不区分大小写的字典,
// this add * should * fail
d.Add(KEY,string.Empty);

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

我们预计这个代码会崩溃,因为不区分大小写的字典会将键和 KEY 作为相同的键,所以会抛出第二个添加。



不幸的是,当所有东西都被编译并运行时,我们得到一个悲伤的面孔:(,因为当 Dictionary WCF层忘记它是用特定的,非默认的, Comparer ,而是获取 string 的默认平等比较器。



是否有一个简单的设置来更改,以便 Comparer 属性字典将被保留,因为它通过电线?或者我必须创建一个自定义类?



(我看过,但这是我的问题,而不是答案)

解决方案

如果你使用标准机制,如添加服务参考等,WCF 按设计将根据 结构创建一个完全独立的复制数据结构 em> ,例如可以在XML模式(XSD)中表达的XML序列化的 结构



这样做不是包含更多的行为(代码)而不是实际数据 - 比如比较等等。



没有设置转就可以了 - 只是不能做到。解决这个问题的唯一方法 - 当你控制通信线的两端,两者都是.NET平台时,是分享双方需要的常用东西(服务合同,数据合同等)服务器以及客户端引用的单独的程序集。在客户端上,您需要确保在创建WCF代理之前添加对之前的共享程序集的引用 - 在这种情况下,WCF运行时将重用现有的数据结构(如您的字典与自定义比较者),而不是创建新的锅炉版副本。


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)

解决方案

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.

这篇关于如何使WCF序列化在通用字典上保留非默认Comparer?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

11-03 12:03