WCF技术剖析(卷1)
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

3.6.1 系统绑定

由于绑定对象由一系列有序的绑定元素组成,绑定元素最终决定着信道栈中信道的组成,而信道的组成最终又决定了信道栈对消息进行处理的方式和能力,所以要确定绑定的特性和能力,我们可以通过查看其绑定元素的构成来一窥究竟。为此我写了一个简单的方法,以列出一个具体绑定对象的所有绑定元素,在介绍一个个具体的系统绑定时,我会使用该方法。

        static void ListAllBindingElements(Binding binding)
        {
            BindingElementCollection elements = binding.CreateBindingElements();
            for (int i = 0; i < elements.Count; i++)
            {
                Console.WriteLine("{0}. {1}", i+1, elements[i].GetType().FullName);
            }
        }

BasicHttpBinding

我们通过调用默认的构造函数创建一个绑定对象,并借助上面的ListAllBindingElements方法列出该绑定对象所有的绑定元素。

        class Program
        {
            static void Main(string[] args)
            {
                BasicHttpBinding binding = new BasicHttpBinding();
                ListAllBindingElements(binding);
            }
        }

将会得到如下的输出,从中可以看出在默认的情况下,一个BasicHttpBinding包含两个最基本的绑定元素:作为传输元素的HttpTransportBindingElement和作为消息编码元素的

TextMessageEncodingBindingElement。所以BasicHttpBinding在默认的情况下采用HTTP和基于文本的消息编码方式。

        1. System.ServiceModel.Channels.TextMessageEncodingBindingElement
        2. System.ServiceModel.Channels.HttpTransportBindingElement

除了提供最基本的传输和编码功能外,BasicHttpBinding还提供了对安全的支持,无论是基于传输的安全还是基于消息的安全,都可以通过对绑定进行相应的设置实现。在下面的代码中,在创建BasicHttpBinding对象的时候,指定一个BasicHttpSecurityMode.Transport参数将安全模式设为传输安全模式。

        class Program
        {
            static void Main(string[] args)
            {
                BasicHttpBinding binding = new BasicHttpBinding(BasicHttpSecurityMode.
                  Transport);
                ListAllBindingElements(binding);
            }
        }

在最终的输出中可以看到,传输绑定元素由HttpTransportBindingElement变成了

HttpsTransportBindingElement,由此可以看出BasicHttpBinding通过HTTPS实现传输安全。

        1. System.ServiceModel.Channels.TextMessageEncodingBindingElement
        2. System.ServiceModel.Channels.HttpsTransportBindingElement

如果我们将其设置成基于消息的安全模式,并将客户端的凭证类型(Client Credential Type)设为证书(Certificate,这对于基于消息安全模式的BasicHttpBinding是必须的)。

        class Program
        {
            static void Main(string[] args)
            {
              BasicHttpBinding binding = new BasicHttpBinding
                  (BasicHttpSecurityMode.Message);
              binding.Security.Message.ClientCredentialType =
                  BasicHttpMessageCredentialType.Certificate;
              ListAllBindingElements(binding);
            }
        }

那么通过输出,我们可以看到在原有绑定元素之上,又多出了一个新的绑定元素:AsymmetricSecurityBindingElement,该元素通过非对称加密(也就是基于X509证书的加密)的方式实现了基于消息的安全。

        1. System.ServiceModel.Channels.AsymmetricSecurityBindingElement
        2. System.ServiceModel.Channels.TextMessageEncodingBindingElement
        3. System.ServiceModel.Channels.HttpTransportBindingElement

对于BasicHttpBinding来说,默认采用基于文本的消息编码方式(TextMessageEncodingBindingElement),实际上BasicHttpBinding还提供基于MTOM编码方式的支持。我们可以通过编程或配置的方式对消息编码方式进行显式指定。在下面的代码中,通过MessageEncoding属性将编码方式指定为:WSMessageEncoding.Mtom。

        class Program
        {
            static void Main(string[] args)
            {
                BasicHttpBinding binding = new BasicHttpBinding();
                binding.MessageEncoding = WSMessageEncoding.Mtom;
                ListAllBindingElements(binding);
            }
        }

那么在最终输出的绑定元素列表中,TextMessageEncodingBindingElement将会被实现MTOM消息编码的MtomMessageEncodingBindingElement代替。

        1. System.ServiceModel.Channels.MtomMessageEncodingBindingElement
        2. System.ServiceModel.Channels.HttpTransportBindingElement

BasicHttpBinding是WS-BP 1.1 Spec标准的,ASP.NET ASMX Web Service的很多标准存在于WS-BP 1.1 Spec中,比如SOAP 1.1、WSDL 1.1、Message Security 1.0等,所以BasicHttpBinding可以和传统的ASP.NET ASMX Web Service进行互操作。

WsHttpBinding

我们先通过下面的方式列出在默认条件下(通过默认的构造函数创建WsHttpBinding对象)该绑定对象具有的所有绑定元素。

        class Program
        {
            static void Main(string[] args)
            {
                WsHttpBinding binding = new WsHttpBinding();
                ListAllBindingElements(binding);
            }
        }

从下面的输出来看,从上到下一共包含4个绑定元素:TransactionFlowBindingElement、SymmetricSecurityBindingElement、TextMessageEncodingBindingElement和HttpTransport-BindingElement。TransactionFlowBindingElement实现了对事务流转;SymmetricSecurity-BindingElement通过对称加密的方式实现基于消息的安全;TextMessageEncodingBinding-Element和HttpTransportBindingElement表明WsHttpBinding和BasicHttpBinding一样采用基于文本的编码方式和基于HTTP的传输协议。

        1. System.ServiceModel.Channels.TransactionFlowBindingElement
        2. System.ServiceModel.Channels.SymmetricSecurityBindingElement
        3. System.ServiceModel.Channels.TextMessageEncodingBindingElement
        4.System.ServiceModel.Channels.HttpTransportBindingElement

在这里须要特别指出的就是WsHttpBinding对事务的支持。对于SOA来说,事务永远是一个重要的主题,我们不仅仅需要单方的事务支持,比如将服务端的操作纳入一个单一的事务之中,也需要事务的流转,将从客户端开始的事务自动流向服务端;不仅仅需要基于单次服务调用的事务,还需要基于多次服务访问的事务(将多次服务调用纳入同一个事务之中);不仅仅需要基于单一平台的事务支持,还需要跨平台的事务(比如将基于.NET平台的WCF服务调用和基于J2EE平台的Web服务调用纳入同一个事务中)。在WS-*体系中,WS-T (Transactions)为事务定义了规范,而在WCF中,则通过TransactionFlowBindingElement实现了WS-Transactions规范。

WsHttpBinding在默认的情况下就提供了基于消息安全的支持,此外WsHttpBinding仍然提供基于HTTPS的传输安全。下面对代码稍加改动,通过构造函数将WsHttpBinding设置为基于传输的安全模式。

        class Program
        {
            static void Main(string[] args)
            {
                WsHttpBinding binding = new WsHttpBinding(SecurityMode.Transport);
                ListAllBindingElements(binding);
            }
        }

那么基于消息模式的SymmetricSecurityBindingElement将被去除,而作为传输绑定元素的HttpTransportBindingElement将被替换成HttpsTransportBindingElement,借此实现基于HTTPS的传输安全。

        1. System.ServiceModel.Channels.TransactionFlowBindingElement
        2. System.ServiceModel.Channels.TextMessageEncodingBindingElement
        3.System.ServiceModel.Channels.HttpsTransportBindingElement

除了提供对传输和消息安全的支持之外,WsHttpBinding还对传输的可靠性提供支持。可靠性消息传输确保在网络环境不好的情况下消息能有效、有序地抵达目的地。WS-*通过WS-RM(Reliable Messaging)为可靠传输定义了规范,在WCF中WS-RM通过可靠会话(Reliable Session)实现了WS-RM,而WS-RM在WCF的实现通过ReliableSessionBindingElement承载。下面的代码中,我们通过另一个构造函数设定WsHttpBinding对可靠会话的支持(第二个参数代表是否支持可靠会话)。

        class Program
        {
            static void Main(string[] args)
            {
                WSHttpBinding binding=new WSHttpBinding(SecurityMode.Message,true);
                ListAllBindingElements(binding);
            }
        }

最终的输出将包含5个绑定元素,第2个就是实现了可靠会话的ReliableSessionBindingElement。

        1.System.ServiceModel.Channels.TransactionFlowBindingElement
        2.System.ServiceModel.Channels.ReliableSessionBindingElement
        3.System.ServiceModel.Channels.SymmetricSecurityBindingElement
        4.System.ServiceModel.Channels.TextMessageEncodingBindingElement
        5.System.ServiceModel.Channels.HttpTransportBindingElement

此外,和BasicHttpBinding一样,WsHttpBinding定义了类型为System.ServiceModel. WSMessageEncoding枚举类型的MessageEncoding属性,有两种WSMessageEncoding枚举值供你选择:Text和MTOM。

综上所述,WsHttpBinding对大部分的WS-*提供支持,这包括上面提到的WS-Transactions、WS-Security、WS-Reliable Messaging等。所以从互操作角度讲,WsHttpBinding可以允许这些标准的Web Service进行互操作。

WsDualHttpBinding

在前面对消息交换模式的介绍中,我们谈到3种典型的消息交换模式:单向的数据报模式、请求/回复模式和双工模式。WsDualHttpBinding就是专门为HTTP传输下双工消息交换模式设计的。

除了基于传输的安全之外,WsHttpBinding的所有特性都被WsDualHttpBinding继承下来,这包括:基于HTTP的传输、基于文本和MTOM的消息编码、WS-Security、WS-Transactions、WS-Reliable Messaging(Reliable Session)等。我们仍然通过输出绑定元素的方式证明这一点。

        class Program
        {
            static void Main(string[] args)
            {
                WSDualHttpBinding binding = new WSDualHttpBinding();
                ListAllBindingElements(binding);
            }
        }

下面列出了输出的所有绑定元素,从中可以看出TransactionFlowBindingElement对WS-Transactions的支持;ReliableSessionBindingElement对WS-RM的支持;SymmetricSecurityBindingElement对WS-Security的支持;这些绑定元素和TextMessageEncodingBindingElement、HttpTransportBindingElement都是与WsHttpBinding共有的,而CompositeDuplexBindingElement和OneWayBindingElement则是WsDualHttpBinding不具有的,这两个绑定元素实现双工通信和单项的数据报模式通信。

        1. System.ServiceModel.Channels.TransactionFlowBindingElement
        2. System.ServiceModel.Channels.ReliableSessionBindingElement
        3. System.ServiceModel.Channels.SymmetricSecurityBindingElement
        4. System.ServiceModel.Channels.CompositeDuplexBindingElement
        5. System.ServiceModel.Channels.OneWayBindingElement
        6. System.ServiceModel.Channels.TextMessageEncodingBindingElement
        7. System.ServiceModel.Channels.HttpTransportBindingElement

对于WsHttpBinding和WsDualHttpBinding的比较,还有一点值得注意的是在默认情况下,WsHttpBinding并没有ReliableSessionBindingElement,也就是说在默认的情况下,WsHttpBinding并不支持可靠会话,而对于基于双工通信的WsDualHttpBinding,可靠会话则是必须的。至于WsDualHttpBinding为何不支持基于传输的安全,原因也很简单,因为HTTP协议下的传输安全通过HTTPS(SSL)实现,HTTPS依赖于一个真正意义上的Web站点,也就是只有访问一个真正意义上Web站点资源的前提下,HTTPS才会有有意义。而对于双工通信来说,由于客户端满足这样要求,所以从服务端回调客户端的传输安全是无法确保的。

双工通信需要一个双工的通信通道,但是属性为TCP/IP的读者应该很清楚,HTTP协议仅仅是一个单纯的请求/回复通信协议,也就是说基于HTTP的通信通道不支持双工通信,那么WsDualHttpBinding又是如何在HTTP传输协议上实现双工通信的呢?答案很简单,WsDualHttpBinding采用了两个HTTP通道。

NetTcpBinding

到此为止,我们一共介绍了3种类型的绑定。从对于传输协议的支持来看,它们都是基于HTTP或HTTPS的绑定;从对标准的支持看来,BasicHttpBinding提供对WS-BP 1.1的支持,WsHttpBinding和WsDualHttpBinding则对WS-*新协议提供很好的支持,比如WS-Transactions、WS-Reliable Messaging、WS-Security等;从消息编码的角度来看,它们均支持基于纯文本的消息编码和MTOM编码。除了WsDualHttpBinding(受到双向通信的制约),这些属性都决定了这两种绑定具有较好的互操作性,也就是说,对于此两种绑定的应用并不限于基于.NET平台应用的交互,如果通过这些绑定寄宿服务,其他平台的客户端可以调用服务,同理我们也可以利用基于这些绑定的客户端访问其他非.NET平台的Web服务,只要对方支持相应的标准。

接下来要介绍的另外3种绑定,相比之下它们就不具有如此好的互操作性了,它们只能应用于单纯的WCF客户端和服务之间的交互。它们基于不同的传输协议,先来介绍基于TCP的NetTcpBinding。

照例采用列出绑定元素列表的方式分析绑定的特性,我们先通过下面的代码看看一个采用默认构造函数创建的NetTcpBinding对象会包含哪些绑定元素。

        class Program
        {
            static void Main(string[] args)
            {
                NetTcpBinding binding = new NetTcpBinding();
                ListAllBindingElements(binding);
            }
        }

程序运行后,下面4个绑定元素会被先后输出。我们借来分析一个NetTcpBinding对象在默认的情况下具有哪些特性:TcpTransportBindingElement表明采用TCP作为传输协议;WindowsStreamSecurityBindingElement提供基于Windows凭证的传输安全;BinaryMessageEncodingBindingElement实现基于二进制的消息编码;TransactionFlowBindingElement则提供对事务流转的支持。

        1. System.ServiceModel.Channels.TransactionFlowBindingElement
        2. System.ServiceModel.Channels.BinaryMessageEncodingBindingElement
        3. System.ServiceModel.Channels.WindowsStreamSecurityBindingElement
        4. System.ServiceModel.Channels.TcpTransportBindingElement

上面涉及的4个绑定元素,除了WindowsStreamSecurityBindingElement外,相信有了前面的介绍,读者对其他3个都不会感到陌生。在这里我们来简单讨论一下WindowsStreamSecurityBindingElement。WindowsStreamSecurityBindingElement继承自System.ServiceModel.Channels.StreamUpgradeBindingElement,StreamUpgradeBindingElement是一种特殊的绑定元素。前面讲了,绑定元素的使命在于对相应信道的创建,而StreamUpgradeBindingElement的特别之处在于它并不参与信道的创建。StreamUpgradeBindingElement一般应用于基于流的传输,比如TCP、命名管道等。它一般位于TransportBindingElement之上,在传输层基础上提供进一步的升级处理(Transport Upgrade),比如安全加密、压缩等。WindowsStreamSecurityBindingElement在这里的提供基于Windows客户端凭证的传输安全,与之相对的,还有一个System.ServiceModel. Channels.SslStreamSecurityBindingElement,它提供基于SSL的传输安全。如果将绑定的客户端凭证的类型改成Certificate或None,SslStreamSecurityBindingElement将会被采用。

        class Program
        {
            static void Main(string[] args)
            {
                NetTcpBinding binding = new NetTcpBinding();
            binding.Security.Transport.ClientCredentialType =
              TcpClientCredentialType.Certificate;
                ListAllBindingElements(binding);
            }
        }

WindowsStreamSecurityBindingElement将会被SslStreamSecurityBindingElement替换。

        1. System.ServiceModel.Channels.TransactionFlowBindingElement
        2. System.ServiceModel.Channels.BinaryMessageEncodingBindingElement
        3. System.ServiceModel.Channels.SslStreamSecurityBindingElement
        4. System.ServiceModel.Channels.TcpTransportBindingElement

除了对传输安全模式的支持(默认),NetTcpBinding也提供对消息安全模式提供支持,比如下面的代码中,再调用构造函数的时候直接将安全模式类型指定为:SecurityMode.Message。

        class Program
        {
            static void Main(string[] args)
            {
                NetTcpBinding binding = new NetTcpBinding(SecurityMode.Message);
                ListAllBindingElements(binding);
            }
        }

实际上,如果采用消息安全模式,SymmetricSecurityBindingElement将会添加实现基于消息级别的签名、加密安全措施。这也可以从下面的输出结果看出来。

        1. System.ServiceModel.Channels.TransactionFlowBindingElement
        2. System.ServiceModel.Channels.SymmetricSecurityBindingElement
        3. System.ServiceModel.Channels.BinaryMessageEncodingBindingElement
        4. System.ServiceModel.Channels.TcpTransportBindingElement

除了单纯的传输安全模式和消息模式之外,NetTcpBinding还支持一种混合的安全模式,该模式的SecurityMode枚举值表示为:SecurityMode.TransportWithMessageCredential。该模式通过传输安全保障数据的一致性和保密性,通过消息安全提供身份验证。关于不同种类的安全模式,将在下一卷“安全”这章中进行详细讲解。SslStreamSecurityBindingElement和TransportSecurityBindingElement一起提供该模式的安全。

        class Program
        {
            static void Main(string[] args)
            {
                NetTcpBinding binding = new NetTcpBinding(SecurityMode.
                  TransportWithMessageCredential);
                ListAllBindingElements(binding);
            }
        }

输出结果:

        1. System.ServiceModel.Channels.TransactionFlowBindingElement
        2. System.ServiceModel.Channels.TransportSecurityBindingElement
        3. System.ServiceModel.Channels.BinaryMessageEncodingBindingElement
        4. System.ServiceModel.Channels.SslStreamSecurityBindingElement
        5. System.ServiceModel.Channels.TcpTransportBindingElement

和WsHttpBinding一样,NetTcpBinding也提供对可靠会话的支持,以保障数据包或消息的可靠、有序传递。不过与WsHttpBinding的实现机制不同的是,NetTcpBinding采用的是TCP协议固有的可靠传输机制,比如消息确认机制、重发机制等。下面的代码,通过ReliableSession.Enabled属性让绑定实现对可靠会话的支持。

        class Program
        {
            static void Main(string[] args)
            {
                NetTcpBinding binding = new NetTcpBinding();
                binding.ReliableSession.Enabled = true;
                ListAllBindingElements(binding);
            }
        }

输出结果:

        1. System.ServiceModel.Channels.TransactionFlowBindingElement
        2. System.ServiceModel.Channels.ReliableSessionBindingElement
        3. System.ServiceModel.Channels.BinaryMessageEncodingBindingElement
        4. System.ServiceModel.Channels.WindowsStreamSecurityBindingElement
        5. System.ServiceModel.Channels.TcpTransportBindingElement

由于NetTcpBinding采用TCP作为传输协议,所以它一般只应用于Intranet中;由于采用二进制的消息编码方式,在性能上较基于文本的编码会有较大的提高;此外,由于和HTTP协议不同,TCP本身就是一个基于双工通信的协议,所以它和WsDualBinding一样,可以用于基于双工消息交换模式的WCF应用中。

NetNamedPipeBinding

NetNamedPipeBinding,顾名思义,就是基于命名管道传输的绑定。命名管道本身可以支持跨机器的通信,而在WCF中对NetNamedPipeBinding做了更加严格的限制,使其只能用于同一台机器的跨进程通信(IPC)。所以在所有的绑定中,NetNamedPipeBinding将是性能最好的绑定类型。

照例通过分析绑定元素的方式来理解绑定本身的特性与能力。先通过下面的代码列出NetNamedPipeBinding默认的绑定元素。

        class Program
        {
            static void Main(string[] args)
            {
                NetNamedPipeBinding binding = new NetNamedPipeBinding();
                ListAllBindingElements(binding);
            }
        }

从输出的绑定元素集合,我们可以得出这样的结论:NamedPipeTransportBindingElement实现了基于命名管道的传输;WindowsStreamSecurityBindingElement提供了基于Windows凭证的传输安全保障;BinaryMessageEncodingBindingElement实现了基于二进制的消息编码;而TransactionFlowBindingElement则为事务流转提供支持。

        1. System.ServiceModel.Channels.TransactionFlowBindingElement
        2. System.ServiceModel.Channels.BinaryMessageEncodingBindingElement
        3. System.ServiceModel.Channels.WindowsStreamSecurityBindingElement
        4. System.ServiceModel.Channels.NamedPipeTransportBindingElement

由于NetNamedPipeBinding的特殊性(提供基于IPC的通信),决定了它的一些相关的特性:仅仅支持传输模式的安全(实际上消息安全模式在IPC场景下已经没有意义);客户端凭证限于Windows。我们可以将安全模式设为None,使其不采用任何安全模式。

        class Program
        {
            static void Main(string[] args)
            {
                NetNamedPipeBinding binding = new NetNamedPipeBinding
                  (NetNamedPipeSecurityMode.None);
                ListAllBindingElements(binding);
            }
        }

这样,WindowsStreamSecurityBindingElement将从绑定元素集合中剔除。

        1. System.ServiceModel.Channels.TransactionFlowBindingElement
        2. System.ServiceModel.Channels.BinaryMessageEncodingBindingElement
        3. System.ServiceModel.Channels.NamedPipeTransportBindingElement

除了上述的5种绑定类型,WCF中还定义了其他一些绑定,比如NetMsmqBinding、MsmqIntegrationBinding、WebHttpBinding等,将会在具体设计到这些特殊的绑定章节中介绍。