• WCF揭秘——自定义绑定


    一、什么是绑定

    绑定是预先配置好的信道栈,它代表了服务器与客户端之间的通信约定,每个绑定都会指定了通信所应用到的传输协调、编码等属性。在Framework3.5中已经包含basicHttpBinding、wsHttpBinding、wsDualHttpBinding、webHttpBinding、netTcpBinding、netNamedPipeBinding、netMsmqBinding、netPeerTcpBinding、msmqIntegrationBinding、wsFedrationHttpBinding、ws2007HttpBinding、ws2007FederationHttpBinding等多种绑定。其中不同的绑定支持不同的传输协议,在消息编码、传输安全、通讯方式、安全模式、可靠性会话、事务流方面有着不同的属性,能够满足大部分信息通讯的要求。

    绑定类名称 传输 编码 消息版本 安全模式 可靠性会话 事务流
    BasicHttpBinding HTTP 文本 SOAP 1.1 不支持 不支持
    WSHttpBinding HTTP 文本 SOAP 1.2 WS-Addressing 1.0 消息 禁用 WS-AtomicTransactions
    WSDualHttpBinding HTTP 文本 SOAP 1.2 WS-Addressing 1.0 消息 启用 WS-AtomicTransactions
    WSFederationHttpBinding HTTP 文本 SOAP 1.2 WS-Addressing 1.0 消息 禁用 WS-AtomicTransactions
    NetTcpBinding TCP 二进制 SOAP 1.2 传输 禁用 OleTransactions
    NetPeerTcpBinding P2P 二进制 SOAP 1.2 传输 不支持 不支持
    NetNamedPipesBinding 命名管道 二进制 SOAP 1.2 传输 不支持 OleTransactions
    NetMsmqBinding MSMQ 二进制 SOAP 1.2 消息 不支持 不支持
    MsmqIntegrationBinding MSMQ 不支持 不支持 传输 不支持 不支持
    CustomBinding 自定义  自定义  自定义 自定义   自定义 自定义

    二、自定义绑定元素

    当预定义的绑定无法满足用户需求时,可以使用CustomBinding类开发自定义绑定,该类存在于System.ServiceModel.Channels命名空间。用户可以根据需要绑定以下属性: 事务(TransactionFlowBindingElement类)、可靠性会话(ReliableSessionBindingElement 类)、安全( SecurityBindingElement 类)、流安全、单工双工工作模式、信息编码、传输绑定等,其中信息编码和传输绑定元素是自定义绑定的必要属性,其他属性用户可根据需求制定。

    • 传输绑定元素(必要),用户可选其中一种传输绑定模式。
    传输信道 传输绑定元素 绑定扩展 配置元素
    TCP传输信道 TcpTransportBindingElement TcpTransportElement <tcpTransport>
    HTTP传输信道 HttpTransportionBindingElement   HttpTransportElement   <httpTransport>
    HTTPS传输信道 HttpTransportationBindingElement HttpTransportElement <httpTransport>
    MSMQ传输信道 MSMQTransportBindingElement MSMQTransportElement <msmqTransport>
    MSMQ集成传输信道 MSMQIntegrationBindingElement   MSMQIntegrationBindingElement <msmqIntegration>
    命名管道传输信道 NamedPipeTransportBindingElement NamedPipeTransportElement   <namedPipeTransport>
    P2P传输信道  PeerTransportBindingElement PeerTransportElement <peerTransport>
    UDP传输信道 UdpTransportBindingElement UdpTransportElement <udpTransport>
    • 信息编码(必要),用户可以选择其中一种信息编码形式

                      1.TextMessageEncodingBindingElement,文本编码

                      2.BinaryMessageEncodingBindingElement,二进制编码

                      3.MtomMessageEncodingBindingElement,MOTM编码

    • 流安全绑定元素(可选),用户可以选择其中一种安全绑定形式

                      1.SslStreamSecurityBindingElement,SSL安全模式

                      2.WindowsStreamSecurityBindingElement,Window安全模式

    • 通信传输(可选),用户可以选择单工或双工其中一种模式

                      1.CompositeDuplexBindingElement,双工传输模式

                      2.OneWayBindingElement,单工传输模式

    CustomBinding相当于一个绑定的容器,用户可以向里面加入想要的绑定元素,定制一组适合使用的绑定方式。用户可以分别使用代码、配置文件和绑定扩展类三种方式来开发自定义绑定,下面为大家一一说明。

     

    三、使用代码定制自定义绑定

    下面以一个最基本的自定义绑定为例子,简单说明一下如何使用代码来定制绑定,首先新建一个服务契约

     1 namespace CustomBinding.Server
    2 {
    3 // 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码和配置文件中的接口名“IExampleService”。
    4 [ServiceContract(Namespace="Services")]
    5 public interface IExampleService
    6 {
    7 [OperationContract]
    8 string HelloWorld(string name);
    9 }
    10
    11 public class ExampleService : IExampleService
    12 {
    13 public string HelloWorld(string name)
    14 {
    15 return "Hello " + name;
    16 }
    17 }
    18 }

    在服务器端,首先新建一个CustomBinding自定义绑定对象,加入传输绑定元素HttpTransportBindingElement,然后加入信息编码元素TextMessageEncodingBindingElement(注意,若使用HttpTransportBindingElement传输方式时,可省略信息编码绑定,那么系统将默认使用TextMessageEncodingBindingElement编码方式)。最后开放元数据,把服务行为的httpGetEnabled设置为true。

     1 namespace CustomBinding.Server
    2 {
    3 class Program
    4 {
    5 static void Main(string[] args)
    6 {
    7 CustomBinding();
    8 }
    9
    10 public static void CustomBinding()
    11 {
    12 using (ServiceHost host = new ServiceHost(typeof(ExampleService), new Uri("http://localhost:8081/Services")))
    13 {
    14 //新建一个CustomBinding对象
    15 System.ServiceModel.Channels.CustomBinding customBinding = new System.ServiceModel.Channels.CustomBinding();
    16 //设置信息编码
    17 customBinding.Elements.Add(new TextMessageEncodingBindingElement());
    18 //设置传输绑定元素
    19 customBinding.Elements.Add(new HttpTransportBindingElement());
    20 //绑定服务契约
    21 host.AddServiceEndpoint(typeof(IExampleService), customBinding, "CustomService");
    22 //开放元数据
    23 ServiceMetadataBehavior behavior = new ServiceMetadataBehavior();
    24 behavior.HttpGetEnabled = true;
    25 host.Description.Behaviors.Add(behavior);
    26 host.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexHttpBinding(), "CustomService/mex");
    27 //启动服务
    28 host.Open();
    29 Console.WriteLine("Service Start!");
    30 Console.ReadKey();
    31 host.Close();
    32 }
    33 }
    34 }

    在客户端添加服务引用,元数据路径“http://localhost:8081/Services/CustomService/mex”,客户端将对应服务生成wsHttpBinding绑定,并使用TextMessageEncodingBindingElement文本编码元素。最后调用服务测试,若测试成功,系统将显示测试结果:“Hello Leslie”。

     1 <?xml version="1.0" encoding="utf-8" ?>
    2 <configuration>
    3 <system.serviceModel>
    4 <bindings>
    5 <!--由于自定义绑定是使用HttpTransportBindingElement绑定元素,所以客户端将自动生成wsHttpBinding设置-->
    6 <wsHttpBinding>
    7 <!--注意绑定元素将对应使用TextMessageEncodingBindingElement信息编码元素-->
    8 <binding name="CustomBinding_IExampleService" closeTimeout="00:01:00"
    9 openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
    10 bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
    11 maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
    12 messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
    13 allowCookies="false">
    14 <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
    15 maxBytesPerRead="4096" maxNameTableCharCount="16384" />
    16 <reliableSession ordered="true" inactivityTimeout="00:10:00"
    17 enabled="false" />
    18 <security mode="None">
    19 <transport clientCredentialType="Windows" proxyCredentialType="None"
    20 realm="" />
    21 <message clientCredentialType="Windows" negotiateServiceCredential="true" />
    22 </security>
    23 </binding>
    24 </wsHttpBinding>
    25 </bindings>
    26 <client>
    27 <endpoint address="http://localhost:8081/Services/CustomService"
    28 binding="wsHttpBinding" bindingConfiguration="CustomBinding_IExampleService"
    29 contract="ExampleService.IExampleService" name="CustomBinding_IExampleService" />
    30 </client>
    31 </system.serviceModel>
    32 </configuration>
    33
    34 namespace CustomBinding.Client
    35 {
    36 class Program
    37 {
    38 static void Main(string[] args)
    39 {
    40 //新建服务对象,调用服务方法
    41 using (ExampleService.ExampleServiceClient example = new ExampleService.ExampleServiceClient())
    42 {
    43 string data=example.HelloWorld("Leslie");
    44 Console.WriteLine(data);
    45 Console.ReadKey();
    46 }
    47 }
    48 }
    49 }



    四、使用配置文件设置自定义绑定

    除了使用代码设置自定义绑定以外,您也可以使用配置文件来设置自定义绑定。下面的例子,将介绍一下如何在自定义绑定中设置可靠性会话功能(关于可靠性会话的详细说明,可参考以下文章http://www.cnblogs.com/leslies2/archive/2011/08/08/2129422.html)。下面依然以上面的例子作为参考,首先在服务器端加入配置文件app.config。加入服务CustomBinding.Server.ExampleService, 绑定服务行为defaultBehavior,在服务行为中打开httpGetEnabled功能。然后把服务地址设置为http://lcoalhost:8082/CustomBinding.Server/ExampleService,加入自定义绑定CustomBinding,绑定契约CustomBinding.Server.IExampleService。最后设置自定义绑定的属性,把可靠性会话时间设置为30分钟,把信息传送方式设置为textMessageEncoding文本方式,把传输通道设置为httpTransport方式。

     1 <?xml version="1.0" encoding="utf-8" ?>
    2 <configuration>
    3 <system.serviceModel>
    4 <services>
    5 <!--根据服务契约类的命名空间设置name名称,设置服务行为defaultBehavior-->
    6 <service name="CustomBinding.Server.ExampleService" behaviorConfiguration="defaultBehavior">
    7 <host>
    8 <baseAddresses>
    9 <!--绑定服务地址-->
    10 <add baseAddress="http://localhost:8082/CustomBinding.Server/ExampleService"/>
    11 </baseAddresses>
    12 </host>
    13 <!--加入自定义绑定-->
    14 <endpoint address="" contract="CustomBinding.Server.IExampleService" binding="customBinding"
    15 bindingConfiguration="customBinding"/>
    16 <!--开放元数据-->
    17 <endpoint address="mex" contract="IMetadataExchange" binding="mexHttpBinding"/>
    18 </service>
    19 </services>
    20 <behaviors>
    21 <serviceBehaviors>
    22 <!--设置服务行为defaultBehavior,把httpGetEnabled设置为true-->
    23 <behavior name="defaultBehavior">
    24 <serviceMetadata httpGetEnabled="true"/>
    25 </behavior>
    26 </serviceBehaviors>
    27 </behaviors>
    28 <bindings>
    29 <customBinding>
    30 <!--设置自定义绑定的属性,把信息编码方式设置为textMessageEncoding文本形式,并把传输通道设置为httpTransport-->
    31 <!--把可靠性会话时间设置为30分钟-->
    32 <binding name="customBinding">
    33 <reliableSession inactivityTimeout="00:30:00"/>
    34 <textMessageEncoding/>
    35 <httpTransport/>
    36 </binding>
    37 </customBinding>
    38 </bindings>
    39 </system.serviceModel>
    40 </configuration>

    设置好config文件后,启动服务

     1 namespace CustomBinding.Server
    2 {
    3 class Program
    4 {
    5 static void Main(string[] args)
    6 {
    7 CustomBinding();
    8 }
    9
    10 public static void CustomBinding()
    11 {
    12 using(ServiceHost host=new ServiceHost(typeof(ExampleService)))
    13 {
    14 Console.WriteLine("Service Start!");
    15 host.Open();
    16 Console.ReadKey();
    17 host.Close();
    18 }
    19 }
    20 }
    21 }

    在客户端添加服务引用,元数据路径“http://lcoalhost:8082/CustomBinding.Server/ExampleService/mex”,客户端将对应服务生成wsHttpBinding绑定,并使用TextMessageEncoding文本编码,值得注意的是客户将对应服务器端生成30分钟可靠性会话。

     1 <?xml version="1.0" encoding="utf-8" ?>
    2 <configuration>
    3 <system.serviceModel>
    4 <bindings>
    5 <!--由于自定义绑定是使用HttpTransportBindingElement绑定元素,所以客户端将自动生成wsHttpBinding设置-->
    6 <wsHttpBinding>
    7 <!--注意绑定元素将对应使用TextMessageEncodingBindingElement信息编码元素-->
    8 <binding name="CustomBinding_IExampleService" closeTimeout="00:01:00"
    9 openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
    10 bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
    11 maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
    12 messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
    13 allowCookies="false">
    14 <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
    15 maxBytesPerRead="4096" maxNameTableCharCount="16384" />
    16 <!--注意客户端将对应服务器端生成30分钟的可靠性会话-->
    17 <reliableSession ordered="true" inactivityTimeout="00:30:00"
    18 enabled="true" />
    19 <security mode="None">
    20 <transport clientCredentialType="Windows" proxyCredentialType="None"
    21 realm="" />
    22 <message clientCredentialType="Windows" negotiateServiceCredential="true" />
    23 </security>
    24 </binding>
    25 </wsHttpBinding>
    26 </bindings>
    27 <client>
    28 <endpoint address="http://localhost:8082/CustomBinding.Server/ExampleService"
    29 binding="wsHttpBinding" bindingConfiguration="CustomBinding_IExampleService"
    30 contract="ExampleService.IExampleService" name="CustomBinding_IExampleService" />
    31 </client>
    32 </system.serviceModel>
    33 </configuration>
    34
    35 namespace CustomBinding.Client
    36 {
    37 class Program
    38 {
    39 static void Main(string[] args)
    40 {
    41 //新建服务对象,调用服务方法
    42 using (ExampleService.ExampleServiceClient example = new ExampleService.ExampleServiceClient())
    43 {
    44 string data=example.HelloWorld("Leslie");
    45 Console.WriteLine(data);
    46 Console.ReadKey();
    47 }
    48 }
    49 }
    50 }


    五、使用绑定扩展类实现自定义绑定

    使用扩展类实现自定义绑定是最灵活,使用最广泛的一种自定义绑定方式,特别适用在大型的分布式系统开发中使用,它可以根据需要实现不同的绑定类型,以适应在各种不同平台上使用。对比起前面两种方法,它的实现方式稍微复杂一些,下而为大家简单介绍一下。在MSDN上有绑定扩展类的开发实例,源代码下载 http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=21459。打开项目\WF_WCF_Samples\WCF\Extensibility\Binding\NetHttpBinding,下面以此为项目例子详细讲述一下绑定扩展类的实现方式。

    其中NetHttpBindingElement继承了StandardBindingElement,它暴露了配置文件中自定义绑定的可配置属性,NetHttpConfigurationStrings中设置了可配置元素的名称,NetHttpDefaults中设置了配置元素的默认值,NetHttpBindingCollectionElements提供配置节的基类,并继承了StandardBindingCollectionElement<NetHttpBinding, NetHttpBindingElement>,可以为NetHttpBindingElement中列举的属性提供预定义绑定。

     1 namespace Microsoft.Samples.NetHttpBinding {
    2
    3 //提供配置节的基类,为NetHttpBindingElement中列举的属性提供预定义绑定
    4 public class NetHttpBindingCollectionElement : StandardBindingCollectionElement<NetHttpBinding, NetHttpBindingElement>
    5 {
    6 }
    7
    8 //列举配置属性的名称
    9 internal class NetHttpConfigurationStrings {
    10
    11 internal const string BypassProxyOnLocal = "bypassProxyOnLocal";
    12
    13 internal const string HostNameComparisonMode = "hostNameComparisonMode";
    14
    15 internal const string MaxBufferSize = "maxBufferSize";
    16
    17 internal const string MaxBufferPoolSize = "maxBufferPoolSize";
    18
    19 internal const string MaxReceivedMessageSize = "maxReceivedMessageSize";
    20
    21 internal const string ProxyAddress = "proxyAddress";
    22
    23 internal const string SecurityMode = "securityMode";
    24
    25 internal const string TransferMode = "transferMode";
    26
    27 internal const string UseDefaultWebProxy = "useDefaultWebProxy";
    28
    29 internal const string ReaderQuotas = "readerQuotas";
    30 }
    31
    32 //设置属性的默认值
    33 internal class NetHttpDefaults {
    34
    35 internal const Boolean DefaultBypassProxyOnLocal = true;
    36
    37 internal const HostNameComparisonMode DefaultHostNameComparisonMode = HostNameComparisonMode.StrongWildcard;
    38
    39 internal const Int32 DefaultMaxBufferSize = 65536;
    40
    41 internal const Int64 DefaultMaxBufferPoolSize = 512 * 1024;
    42
    43 internal const Int64 DefaultMaxReceivedMessageSize = 65536;
    44
    45 internal const Uri DefaultProxyAddress = null;
    46
    47 internal const NetHttpSecurityMode DefaultSecurityMode = NetHttpSecurityMode.Transport;
    48
    49 internal const TransferMode DefaultTransferMode = TransferMode.Buffered;
    50
    51 internal const Boolean DefaultUseDefaultWebProxy = true;
    52
    53 internal const XmlDictionaryReaderQuotas DefaultReaderQuotas = null;
    54 }
    55
    56 //列举安全模式
    57 public enum NetHttpSecurityMode
    58 {
    59 Transport,
    60 TransportCredentialOnly,
    61 None
    62 }
    63 }

    注意若需要在通过*.config文件配置的属性,都必须在NetHttpBindingElement类中一一列举。NetHttpBindingElement必须实现InitializeFrom和OnApplyConfiguration方法,InitializeFrom方法是使用默认值初始化绑定配置元素,而OnApplyConfiguration是在绑定配置文件时调用的方法,必须实现此方法才能使配置文件的绑定属性生效。

      1 namespace Microsoft.Samples.NetHttpBinding {
    2
    3 public class NetHttpBindingElement : StandardBindingElement {
    4
    5 public NetHttpBindingElement(string configurationName) :
    6 base(configurationName) {
    7 }
    8
    9 public NetHttpBindingElement()
    10 :
    11 this(null) {
    12 }
    13
    14 protected override Type BindingElementType {
    15 get {
    16 return typeof(NetHttpBinding);
    17 }
    18 }
    19
    20 //利用NetHttpConfigurationStrings类设置绑定文件属性名称,利用DefaultValue类设置默认值
    [ConfigurationProperty(NetHttpConfigurationStrings.BypassProxyOnLocal, DefaultValue = NetHttpDefaults.DefaultBypassProxyOnLocal)]

    21 public bool BypassProxyOnLocal {
    22 get {
    23 return ((bool)(base[NetHttpConfigurationStrings.BypassProxyOnLocal]));
    24 }
    25 set {
    26 base[NetHttpConfigurationStrings.BypassProxyOnLocal] = value;
    27 }
    28 }
    29
    30 //利用NetHttpConfigurationStrings类设置绑定文件属性名称,利用DefaultValue类设置默认值
    [ConfigurationProperty(NetHttpConfigurationStrings.HostNameComparisonMode, DefaultValue = NetHttpDefaults.DefaultHostNameComparisonMode)]

    31 public System.ServiceModel.HostNameComparisonMode HostNameComparisonMode {
    32 get {
    33 return ((System.ServiceModel.HostNameComparisonMode)(base[NetHttpConfigurationStrings.HostNameComparisonMode]));
    34 }
    35 set {
    36 base[NetHttpConfigurationStrings.HostNameComparisonMode] = value;
    37 }
    38 }
    39
    40 //利用NetHttpConfigurationStrings类设置绑定文件属性名称,利用DefaultValue类设置默认值
     [ConfigurationProperty(NetHttpConfigurationStrings.MaxBufferSize, DefaultValue = NetHttpDefaults.DefaultMaxBufferSize)]

    41 public int MaxBufferSize {
    42 get {
    43 return ((int)(base[NetHttpConfigurationStrings.MaxBufferSize]));
    44 }
    45 set {
    46 base[NetHttpConfigurationStrings.MaxBufferSize] = value;
    47 }
    48 }
    49
    50 //利用NetHttpConfigurationStrings类设置绑定文件属性名称,利用DefaultValue类设置默认值
    [ConfigurationProperty(NetHttpConfigurationStrings.MaxBufferPoolSize, DefaultValue = NetHttpDefaults.DefaultMaxBufferPoolSize)]

    51 public long MaxBufferPoolSize {
    52 get {
    53 return ((long)(base[NetHttpConfigurationStrings.MaxBufferPoolSize]));
    54 }
    55 set {
    56 base[NetHttpConfigurationStrings.MaxBufferPoolSize] = value;
    57 }
    58 }
    59
    60 //利用NetHttpConfigurationStrings类设置绑定文件属性名称,利用DefaultValue类设置默认值
    [ConfigurationProperty(NetHttpConfigurationStrings.MaxReceivedMessageSize, DefaultValue = NetHttpDefaults.DefaultMaxReceivedMessageSize)]

    61 public long MaxReceivedMessageSize {

    62 get {
    63 return ((long)(base[NetHttpConfigurationStrings.MaxReceivedMessageSize]));
    64 }
    65 set {
    66 base[NetHttpConfigurationStrings.MaxReceivedMessageSize] = value;
    67 }
    68 }
    69
    70 //利用NetHttpConfigurationStrings类设置绑定文件属性名称,利用DefaultValue类设置默认值
     [ConfigurationProperty(NetHttpConfigurationStrings.ProxyAddress, DefaultValue = NetHttpDefaults.DefaultProxyAddress)]

    71 public System.Uri ProxyAddress {
    72 get {
    73 return ((System.Uri)(base[NetHttpConfigurationStrings.ProxyAddress]));
    74 }
    75 set {
    76 base[NetHttpConfigurationStrings.ProxyAddress] = value;
    77 }
    78 }
    79
    80 //利用NetHttpConfigurationStrings类设置绑定文件属性名称,利用DefaultValue类设置默认值
    81 [ConfigurationProperty(NetHttpConfigurationStrings.SecurityMode, DefaultValue = NetHttpDefaults.DefaultSecurityMode)]
    82 public Microsoft.Samples.NetHttpBinding.NetHttpSecurityMode SecurityMode {
    83 get {
    84 return ((Microsoft.Samples.NetHttpBinding.NetHttpSecurityMode)(base[NetHttpConfigurationStrings.SecurityMode]));
    85 }
    86 set {
    87 base[NetHttpConfigurationStrings.SecurityMode] = value;
    88 }
    89 }
    90
    91 //利用NetHttpConfigurationStrings类设置绑定文件属性名称,利用DefaultValue类设置默认值
    92 [ConfigurationProperty(NetHttpConfigurationStrings.TransferMode, DefaultValue = NetHttpDefaults.DefaultTransferMode)]
    93 public System.ServiceModel.TransferMode TransferMode {
    94 get {
    95 return ((System.ServiceModel.TransferMode)(base[NetHttpConfigurationStrings.TransferMode]));
    96 }
    97 set {
    98 base[NetHttpConfigurationStrings.TransferMode] = value;
    99 }
    100 }
    101
    102 //利用NetHttpConfigurationStrings类设置绑定文件属性名称,利用DefaultValue类设置默认值
    [ConfigurationProperty(NetHttpConfigurationStrings.UseDefaultWebProxy, DefaultValue = NetHttpDefaults.DefaultUseDefaultWebProxy)]

    103 public bool UseDefaultWebProxy {
    104 get {
    105 return ((bool)(base[NetHttpConfigurationStrings.UseDefaultWebProxy]));
    106 }
    107 set {
    108 base[NetHttpConfigurationStrings.UseDefaultWebProxy] = value;
    109 }
    110 }
    111
    112 //利用NetHttpConfigurationStrings类设置绑定文件属性名称,利用DefaultValue类设置默认值
     [ConfigurationProperty(NetHttpConfigurationStrings.ReaderQuotas, DefaultValue = NetHttpDefaults.DefaultReaderQuotas)]

    113 public System.Xml.XmlDictionaryReaderQuotas ReaderQuotas {
    114 get {
    115 return ((System.Xml.XmlDictionaryReaderQuotas)(base[NetHttpConfigurationStrings.ReaderQuotas]));
    116 }
    117 set {
    118 base[NetHttpConfigurationStrings.ReaderQuotas] = value;
    119 }
    120 }
    121
    122 //设置绑定属性
    123 protected override ConfigurationPropertyCollection Properties {
    124 get {
    125 ConfigurationPropertyCollection properties = base.Properties;
    126 properties.Add(new ConfigurationProperty(NetHttpConfigurationStrings.BypassProxyOnLocal, typeof(bool), NetHttpDefaults.DefaultBypassProxyOnLocal));
    127 properties.Add(new ConfigurationProperty(NetHttpConfigurationStrings.HostNameComparisonMode, typeof(System.ServiceModel.HostNameComparisonMode), NetHttpDefaults.DefaultHostNameComparisonMode));
    128 properties.Add(new ConfigurationProperty(NetHttpConfigurationStrings.MaxBufferSize, typeof(int), NetHttpDefaults.DefaultMaxBufferSize));
    129 properties.Add(new ConfigurationProperty(NetHttpConfigurationStrings.MaxBufferPoolSize, typeof(long), NetHttpDefaults.DefaultMaxBufferPoolSize));
    130 properties.Add(new ConfigurationProperty(NetHttpConfigurationStrings.MaxReceivedMessageSize, typeof(long), NetHttpDefaults.DefaultMaxReceivedMessageSize));
    131 properties.Add(new ConfigurationProperty(NetHttpConfigurationStrings.ProxyAddress, typeof(System.Uri), NetHttpDefaults.DefaultProxyAddress));
    132 properties.Add(new ConfigurationProperty(NetHttpConfigurationStrings.SecurityMode, typeof(Microsoft.Samples.NetHttpBinding.NetHttpSecurityMode), NetHttpDefaults.DefaultSecurityMode));
    133 properties.Add(new ConfigurationProperty(NetHttpConfigurationStrings.TransferMode, typeof(System.ServiceModel.TransferMode), NetHttpDefaults.DefaultTransferMode));
    134 properties.Add(new ConfigurationProperty(NetHttpConfigurationStrings.UseDefaultWebProxy, typeof(bool), NetHttpDefaults.DefaultUseDefaultWebProxy));
    135 properties.Add(new ConfigurationProperty(NetHttpConfigurationStrings.ReaderQuotas, typeof(System.Xml.XmlDictionaryReaderQuotas), NetHttpDefaults.DefaultReaderQuotas));
    136 return properties;
    137 }
    138 }
    139
    140 //设置默认值
    141 protected override void InitializeFrom(Binding binding) {
    142 base.InitializeFrom(binding);
    143 NetHttpBinding netHttpBinding = ((NetHttpBinding)(binding));
    144 this.BypassProxyOnLocal = netHttpBinding.BypassProxyOnLocal;
    145 this.HostNameComparisonMode = netHttpBinding.HostNameComparisonMode;
    146 this.MaxBufferSize = netHttpBinding.MaxBufferSize;
    147 this.MaxBufferPoolSize = netHttpBinding.MaxBufferPoolSize;
    148 this.MaxReceivedMessageSize = netHttpBinding.MaxReceivedMessageSize;
    149 this.ProxyAddress = netHttpBinding.ProxyAddress;
    150 this.SecurityMode = netHttpBinding.SecurityMode;
    151 this.TransferMode = netHttpBinding.TransferMode;
    152 this.UseDefaultWebProxy = netHttpBinding.UseDefaultWebProxy;
    153 this.ReaderQuotas = netHttpBinding.ReaderQuotas;
    154 }
    155
    156 //在绑定配置文件时发生
    157 protected override void OnApplyConfiguration(Binding binding) {
    158 if ((binding == null)) {
    159 throw new System.ArgumentNullException("binding");
    160 }
    161 if ((binding.GetType() != typeof(NetHttpBinding))) {
    162 throw new System.ArgumentException(string.Format(CultureInfo.CurrentCulture, "Invalid type for binding. Expected type: {0}. Type passed in: {1}.", typeof(NetHttpBinding).AssemblyQualifiedName, binding.GetType().AssemblyQualifiedName));
    163 }
    164 NetHttpBinding netHttpBinding = ((NetHttpBinding)(binding));
    165 netHttpBinding.BypassProxyOnLocal = this.BypassProxyOnLocal;
    166 netHttpBinding.HostNameComparisonMode = this.HostNameComparisonMode;
    167 netHttpBinding.MaxBufferSize = this.MaxBufferSize;
    168 netHttpBinding.MaxBufferPoolSize = this.MaxBufferPoolSize;
    169 netHttpBinding.MaxReceivedMessageSize = this.MaxReceivedMessageSize;
    170 netHttpBinding.ProxyAddress = this.ProxyAddress;
    171 netHttpBinding.SecurityMode = this.SecurityMode;
    172 netHttpBinding.TransferMode = this.TransferMode;
    173 netHttpBinding.UseDefaultWebProxy = this.UseDefaultWebProxy;
    174 netHttpBinding.ReaderQuotas = this.ReaderQuotas;
    175 }
    176 }
    177 }

    NetHttpBinding类是实现绑定扩展的核心,首先它实现了NetHttpBindingElement类中所包含BypassProxyOnLocal、HostNameComparisonMode、MaxBufferSize、MaxBufferPoolSize.......等等属性,这使得系统可以通过NetHttpBinding类设置绑定属性。

      1 public class NetHttpBinding: : Binding, ISecurityCapabilities
    2 {
    3 public bool BypassProxyOnLocal
    4 {
    5 get { return httpTransport.BypassProxyOnLocal; }
    6 set
    7 {
    8 httpTransport.BypassProxyOnLocal = value;
    9 httpsTransport.BypassProxyOnLocal = value;
    10 }
    11 }
    12
    13 public HostNameComparisonMode HostNameComparisonMode
    14 {
    15 get { return httpTransport.HostNameComparisonMode; }
    16 set
    17 {
    18 httpTransport.HostNameComparisonMode = value;
    19 httpsTransport.HostNameComparisonMode = value;
    20 }
    21 }
    22
    23 public int MaxBufferSize
    24 {
    25 get { return httpTransport.MaxBufferSize; }
    26 set
    27 {
    28 httpTransport.MaxBufferSize = value;
    29 httpsTransport.MaxBufferSize = value;
    30 }
    31 }
    32
    33 public long MaxBufferPoolSize
    34 {
    35 get { return httpTransport.MaxBufferPoolSize; }
    36 set
    37 {
    38 httpTransport.MaxBufferPoolSize = value;
    39 httpsTransport.MaxBufferPoolSize = value;
    40 }
    41 }
    42
    43 public long MaxReceivedMessageSize
    44 {
    45 get { return httpTransport.MaxReceivedMessageSize; }
    46 set
    47 {
    48 httpTransport.MaxReceivedMessageSize = value;
    49 httpsTransport.MaxReceivedMessageSize = value;
    50 }
    51 }
    52
    53 public Uri ProxyAddress
    54 {
    55 get { return httpTransport.ProxyAddress; }
    56 set
    57 {
    58 httpTransport.ProxyAddress = value;
    59 httpsTransport.ProxyAddress = value;
    60 }
    61 }
    62
    63 public NetHttpSecurityMode SecurityMode
    64 {
    65 get { return this.securityMode; }
    66 set
    67 {
    68 if (value != NetHttpSecurityMode.Transport &&
    69 value != NetHttpSecurityMode.TransportCredentialOnly &&
    70 value != NetHttpSecurityMode.None)
    71 {
    72 throw new ArgumentOutOfRangeException("value");
    73 }
    74 this.securityMode = value;
    75 }
    76 }
    77
    78 public TransferMode TransferMode
    79 {
    80 get { return httpTransport.TransferMode; }
    81 set
    82 {
    83 httpTransport.TransferMode = value;
    84 httpsTransport.TransferMode = value;
    85 }
    86 }
    87
    88 public bool UseDefaultWebProxy
    89 {
    90 get { return httpTransport.UseDefaultWebProxy; }
    91 set
    92 {
    93 httpTransport.UseDefaultWebProxy = value;
    94 httpsTransport.UseDefaultWebProxy = value;
    95 }
    96 }
    97
    98 public XmlDictionaryReaderQuotas ReaderQuotas
    99 {
    100 get { return binaryEncoding.ReaderQuotas; }
    101 set
    102 {
    103 if (value != null)
    104 {
    105 value.CopyTo(binaryEncoding.ReaderQuotas);
    106 }
    107 }
    108 }
    109
    110 public EnvelopeVersion EnvelopeVersion
    111 {
    112 get { return EnvelopeVersion.Soap12; }
    113 }
    ........................
    ........................
    114 }

    其次,它继承了Binding类,Binding类中包含的CloseTimeout、MessageVersion、OpenTimeout、ReceiveTimeout.......等等属性都可以通过NetHttpBinding设置。值得注意的是,Binding类的Scheme属性必需在NetHttpBinding中实现,此属性是用于绑定通道中所使用到的传输的。而CreateBindingElements方法则是用于创建当前的绑定元素。

     1  public class NetHttpBinding : Binding, ISecurityCapabilities
    2 {
    3 HttpTransportBindingElement httpTransport;
    4 HttpsTransportBindingElement httpsTransport;
    5 BinaryMessageEncodingBindingElement binaryEncoding;
    6
    7 NetHttpSecurityMode securityMode;
    8
    9 public NetHttpBinding() : this(NetHttpSecurityMode.Transport)
    10 {
    11 }
    12 public NetHttpBinding(string configurationName) : this()
    13 {
    14 ApplyConfiguration(configurationName);
    15 }
    16
    17 public NetHttpBinding(NetHttpSecurityMode securityMode)
    18 {
    19 if (securityMode != NetHttpSecurityMode.Transport &&
    20 securityMode != NetHttpSecurityMode.TransportCredentialOnly &&
    21 securityMode != NetHttpSecurityMode.None)
    22 {
    23 throw new ArgumentOutOfRangeException("securityMode");
    24 }
    25
    26 this.securityMode = securityMode;
    27 this.httpTransport = new HttpTransportBindingElement();
    28 this.httpsTransport = new HttpsTransportBindingElement();
    29 this.binaryEncoding = new BinaryMessageEncodingBindingElement();
    30 }
    31
    32 //绑定通道中所用到的传输
    33 public override string Scheme
    34 {
    35 get
    36 {
    37 if (securityMode == NetHttpSecurityMode.Transport)
    38 {
    39 return httpsTransport.Scheme;
    40 }
    41 else
    42 {
    43 return httpTransport.Scheme;
    44 }
    45 }
    46 }
    47
    48 //创建当前绑定元素
    49 public override BindingElementCollection CreateBindingElements()
    50 { // return collection of BindingElements
    51 BindingElementCollection bindingElements = new BindingElementCollection();
    52 bindingElements.Add(binaryEncoding);
    53
    54 if (this.securityMode == NetHttpSecurityMode.Transport)
    55 {
    56 bindingElements.Add(this.httpsTransport);
    57 }
    58 else
    59 {
    60 if (this.securityMode == NetHttpSecurityMode.TransportCredentialOnly)
    61 {
    62 this.httpTransport.AuthenticationScheme = AuthenticationSchemes.Negotiate;
    63 }
    64 else
    65 {
    66 this.httpTransport.AuthenticationScheme = AuthenticationSchemes.Anonymous;
    67 }
    68 bindingElements.Add(this.httpTransport);
    69 }
    70
    71 return bindingElements.Clone();
    72 }
    73 ...............
    74 ...............
    75 }

    再次,NetHttpBinding实现了ISecurityCapabilityies接口,此接口是用于设置安全功能协议的。它包含以下几个属性,这些属性都将在NetHttpBinding中实现。

    属性说明
    SupportedRequestProtectionLevel 获取绑定支持的保护级别请求。
    SupportedResponseProtectionLevel 获取绑定支持的保护级别响应。
    SupportsClientAuthentication 获取一个值,该值指示绑定是否支持客户端身份验证。
    SupportsClientWindowsIdentity 获取一个值,该值指示绑定是否支持客户端 Windows 标识。
    SupportsServerAuthentication 获取一个值,该值指示绑定是否支持服务器身份验证。
     1  public class NetHttpBinding : Binding, ISecurityCapabilities
    2 {
    3 System.Net.Security.ProtectionLevel ISecurityCapabilities.SupportedRequestProtectionLevel
    4 {
    5 get
    6 {
    7 if (securityMode == NetHttpSecurityMode.Transport)
    8 {
    9 return ProtectionLevel.EncryptAndSign;
    10 }
    11 else
    12 {
    13 return ProtectionLevel.None;
    14 }
    15 }
    16 }
    17
    18 System.Net.Security.ProtectionLevel ISecurityCapabilities.SupportedResponseProtectionLevel
    19 {
    20 get
    21 {
    22 if (securityMode == NetHttpSecurityMode.Transport)
    23 {
    24 return ProtectionLevel.EncryptAndSign;
    25 }
    26 else
    27 {
    28 return ProtectionLevel.None;
    29 }
    30 }
    31 }
    32
    33 bool ISecurityCapabilities.SupportsClientAuthentication
    34 {
    35 get
    36 {
    37 if (securityMode == NetHttpSecurityMode.None)
    38 {
    39 return false;
    40 }
    41 else
    42 {
    43 return true;
    44 }
    45 }
    46 }
    47
    48 bool ISecurityCapabilities.SupportsClientWindowsIdentity
    49 {
    50 get
    51 {
    52 if (securityMode == NetHttpSecurityMode.None)
    53 {
    54 return false;
    55 }
    56 else
    57 {
    58 return true;
    59 }
    60 }
    61 }
    62
    63 bool ISecurityCapabilities.SupportsServerAuthentication
    64 {
    65 get
    66 {
    67 if (securityMode == NetHttpSecurityMode.None)
    68 {
    69 return false;
    70 }
    71 else
    72 {
    73 return true;
    74 }
    75 }
    76 }
    ...................
    77 }

    最后,NetHttpBinding实现 ApplyConfiguration 方法,使系统可以使用配置文件*.config来设置NetHttpBinding的属性。

     1  public class NetHttpBinding : Binding, ISecurityCapabilities
    2 {
    3 private void ApplyConfiguration(string configurationName)
    4 {
    5 BindingsSection bindings = ((BindingsSection)(ConfigurationManager.GetSection("system.serviceModel/bindings")));
    6 NetHttpBindingCollectionElement section = (NetHttpBindingCollectionElement)bindings["netHttpBinding"];
    7 NetHttpBindingElement element = section.Bindings[configurationName];
    8 if ((element == null))
    9 {
    10 throw new System.Configuration.ConfigurationErrorsException(string.Format(CultureInfo.CurrentCulture, "There is no binding named {0} at {1}.", configurationName, section.BindingName));
    11 }
    12 else
    13 {
    14 element.ApplyConfiguration(this);
    15 }
    16 }
    .....................
    17 }

    当完成自定义绑定后,可以开始尝试在服务器端启动服务

     1 namespace Microsoft.Samples.NetHttpBinding
    2 {
    3 [ServiceContract]
    4 public interface IEchoService
    5 {
    6 [OperationContract]
    7 string Echo(string message);
    8 }
    9
    10 class Service
    11 {
    12 //设置服务的基础URI
    13 static readonly UriBuilder uriBuilder = new UriBuilder("http://" + Environment.MachineName + ":8000/TestService");
    14 static void Main(string[] args)
    15 {
    16 //创建自定义绑定对象
    17 NetHttpBinding httpsBinding = new NetHttpBinding();
    18 //设置绑定对象的安全模式
    19 NetHttpBinding httpBinding = new NetHttpBinding(NetHttpSecurityMode.TransportCredentialOnly);
    20 //加入服务对象 ,绑定服务地址
    21 ServiceHost serviceHost = new ServiceHost(typeof(EchoService), GetBaseAddress("http", 8000), GetBaseAddress("https", 8443));
    22 serviceHost.AddServiceEndpoint(typeof(IEchoService), httpBinding, "BinaryEncoderOverHTTP");
    23 serviceHost.AddServiceEndpoint(typeof(IEchoService), httpsBinding, "BinaryEncoderOverHTTPS");
    24 serviceHost.Open();
    25
    26 Console.WriteLine("Service started at: " + serviceHost.ChannelDispatchers[0].Listener.Uri.AbsoluteUri);
    27 Console.WriteLine("Service started at: " + serviceHost.ChannelDispatchers[1].Listener.Uri.AbsoluteUri);
    28 Console.WriteLine("Press enter to exit...");
    29 Console.ReadLine();
    30 }
    31 static Uri GetBaseAddress(string scheme, int port)
    32 {
    33 uriBuilder.Scheme = scheme;
    34 uriBuilder.Port = port;
    35 return uriBuilder.Uri;
    36 }
    37 }
    38
    39 //实现服务契约
    40 class EchoService : IEchoService
    41 {
    42 #region IEchoService Members
    43
    44 public string Echo(string message)
    45 {
    46 Console.WriteLine("Echo called with: " + message);
    47
    48 Console.WriteLine("The client is hitting endpoint: {0}", OperationContext.Current.IncomingMessageProperties.Via.AbsoluteUri);
    49 ServiceSecurityContext securityContext = OperationContext.Current.ServiceSecurityContext;
    50 Console.WriteLine("The client is: {0}", securityContext.IsAnonymous ? "anonymous" : securityContext.PrimaryIdentity.Name);
    51 return message;
    52 }
    53
    54 #endregion
    55 }
    56 }

    在MSDN中已经有此开发实例,在此也不再作详细解释。致此,已经对自定义绑定作出详细的说明,用户可以分别使用代码、配置文件和绑定扩展类三种方式来开发自定义绑定。在使用复杂的面向服务开发系统中实现自定义绑定,可以按照不同的需求实现服务,绑定不同的传输协调,文本传输方式,限制最大传输流量等,不失为实现分布式开发的一种手段。

    相关文章

    自定义绑定

    简单的WCF开发实例

    使用AJAX+WCF进行页面开发

    共享数据契约

    可靠性会话功能

    对JAVA与.NET开发有兴趣的朋友欢迎加入QQ群:162338858 点击这里加入此群

    cnblogs博客园:http://www.cnblogs.com/leslies2/
    csdn博客:http://blog.csdn.net/leslies2
    原创作品,转载时请注明作者及出处



  • 相关阅读:
    完整java开发中JDBC连接数据库代码和步骤
    2007最后一贴
    ajax数据加载经验分享
    vs2008中文版提供下载(包含中文msdn)
    修改服务器控件的ID和Name
    你使用控件吗?会用吗?
    自定义控件集
    asp.net控件开发基础示例代码打包
    javascript好文章收藏
    wpf学习笔记简单绑定
  • 原文地址:https://www.cnblogs.com/leslies2/p/2195800.html
Copyright © 2020-2023  润新知