WCF中的Binding模型之六(完结篇):从绑定元素认识系统预定义绑定

  1. 云栖社区>
  2. 博客>
  3. 正文

WCF中的Binding模型之六(完结篇):从绑定元素认识系统预定义绑定

行者武松 2017-10-30 14:57:42 浏览1182

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

   1: static void ListAllBindingElements(Binding binding)
   2: {
   3:     BindingElementCollection elements = binding.CreateBindingElements();
   4:     for (int i = 0; i < elements.Count; i++)
   5:     {
   6: Console.WriteLine("{0}. {1}", i+1, elements[i].GetType().FullName);
   7:     }
   8: }

 

一、BasicHttpBinding

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

   1: class Program
   2: {
   3:     static void Main(string[] args)
   4:     {
   5:         BasicHttpBinding binding = new BasicHttpBinding();
   6:         ListAllBindingElements(binding);
   7:     }
   8: }

 

将会得到如下的输出,从中可以看出在默认的情况下,一个BasicHttpBinding包含两个最基本的绑定元素:最为传输元素的HttpTransportBindingElement和作为消息编码元素的TextMessageEncodingBindingElement。所以BasicHttpBinding在默认的情况下采用HTTP传输协议,和基于文本的消息编码方式。之所以将此绑定命名为BasicHttpBinding,很大程度上缘于它仅仅包含一些最基本的用于消息通信的元素。


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

   1: class Program
   2: {
   3:     static void Main(string[] args)
   4:     {
   5:         BasicHttpBinding binding = new BasicHttpBinding(BasicHttpSecurityMode.Transport);
   6:         ListAllBindingElements(binding);
   7:     }
   8: }

 

在最终的输出中我们可以看到,传输绑定元素由HttpTransportBindingElement变成了HttpsTransportBindingElement,由此可以看出BasicHttpBinding通过HTTPS实现传输安全。


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

   1: class Program
   2: {
   3:     static void Main(string[] args)
   4:     {
   5:         BasicHttpBinding binding = new BasicHttpBinding(BasicHttpSecurityMode.Message);
   6:         binding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.Certificate;
   7:         ListAllBindingElements(binding);
   8:     }
   9: }

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


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

   1: class Program
   2: {
   3:     static void Main(string[] args)
   4:     {
   5:         BasicHttpBinding binding = new BasicHttpBinding();
   6:         binding.MessageEncoding = WSMessageEncoding.Mtom;
   7:         ListAllBindingElements(binding);
   8:     }
   9: }

 

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


BasicHttpBinding是WS-BP 1.1 Spec (Basic Profile) 标准的,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

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

   1: class Program
   2: {
   3:     static void Main(string[] args)
   4:     {
   5:         WsHttpBinding binding = new WsHttpBinding();
   6:         ListAllBindingElements(binding);
   7:     }
   8: }

 

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


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

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

   1: class Program
   2: {
   3:     static void Main(string[] args)
   4:     {
   5:         WsHttpBinding binding = new WsHttpBinding(SecurityMode.Transport);
   6:         ListAllBindingElements(binding);
   7:     }
   8: }

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


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

   1: class Program
   2: {
   3:     static void Main(string[] args)
   4:     {
   5:         WSHttpBinding binding = new WSHttpBinding(SecurityMode.Message, true);
   6:         ListAllBindingElements(binding);
   7:     }
   8: }

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



 

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

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

三、 WsDualHttpBinding

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

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

   1: class Program
   2: {
   3:     static void Main(string[] args)
   4:     {
   5:         WSDualHttpBinding binding = new WSDualHttpBinding();
   6:         ListAllBindingElements(binding);
   7:     }
   8: }

 

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


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

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

四、NetTcpBinding

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

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

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

   1: class Program
   2: {
   3:     static void Main(string[] args)
   4:     {
   5:         NetTcpBinding binding = new NetTcpBinding();
   6:         ListAllBindingElements(binding);
   7:     }
   8: }

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


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

   1: class Program
   2: {
   3:     static void Main(string[] args)
   4:     {
   5:         NetTcpBinding binding = new NetTcpBinding();
   6:         binding.Security.Transport.ClientCredentialType = TcpClientCredentialType.Certificate;
   7:         ListAllBindingElements(binding);
   8:     }
   9: }

WindowsStreamSecurityBindingElement将会被SslStreamSecurityBindingElement替换:

 

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

   1: class Program
   2: {
   3:     static void Main(string[] args)
   4:     {
   5:         NetTcpBinding binding = new NetTcpBinding(SecurityMode.Message);
   6:         ListAllBindingElements(binding);
   7:     }
   8: }

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

 


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

   1: class Program
   2: {
   3:     static void Main(string[] args)
   4:     {
   5:         NetTcpBinding binding = new NetTcpBinding(SecurityMode.TransportWithMessageCredential);
   6:         ListAllBindingElements(binding);
   7:     }
   8: }

输出结果:



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

   1: class Program
   2: {
   3:     static void Main(string[] args)
   4:     {
   5:         NetTcpBinding binding = new NetTcpBinding();
   6:         binding.ReliableSession.Enabled = true;
   7:         ListAllBindingElements(binding);
   8:     }
   9: }

和WsHttpBinding一样,通过ReliableSessionBindingElement实现对可靠会话的支持:


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

五、 NetNamedPipeBinding

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

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

   1: class Program
   2: {
   3:     static void Main(string[] args)
   4:     {
   5:         NetNamedPipeBinding binding = new NetNamedPipeBinding();
   6:         ListAllBindingElements(binding);
   7:     }
   8: }

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


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

   1: class Program
   2: {
   3:     static void Main(string[] args)
   4:     {
   5:         NetNamedPipeBinding binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None);
   6:         ListAllBindingElements(binding);
   7:     }
   8: }

 

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


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

WCF中的绑定模型:
[WCF中的Binding模型]之一: Binding模型简介
[WCF中的Binding模型]之二: 信道与信道栈(Channel and Channel Stack)
[WCF中的Binding模型]之三:信道监听器(Channel Listener)
[WCF中的Binding模型]之四:信道工厂(Channel Factory)
[WCF中的Binding模型]之五:绑定元素(Binding Element)
[WCF中的Binding模型]之六:从绑定元素认识系统预定义绑定



作者:蒋金楠
微信公众账号:大内老A
微博:www.weibo.com/artech
如果你想及时得到个人撰写文章以及著作的消息推送,或者想看看个人推荐的技术资料,可以扫描左边二维码(或者长按识别二维码)关注个人公众号(原来公众帐号蒋金楠的自媒体将会停用)。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
原文链接