当预定义的绑定无法满足用户需求时,可以使用CustomBinding类开发自定义绑定,该类存在于System.ServiceModel.Channels命名空间。用户可以根据需要绑定以下属性: 事务(TransactionFlowBindingElement类)、可靠性会话(ReliableSessionBindingElement 类)、安全( SecurityBindingElement 类)、流安全、单工双工工作模式、信息编码、传输绑定等,其中信息编码和传输绑定元素是自定义绑定的必要属性,其他属性用户可根据需求制定。
一、什么是绑定
绑定是预先配置好的信道栈,它代表了服务器与客户端之间的通信约定,每个绑定都会指定了通信所应用到的传输协调、编码等属性。在Framework3.5中已经包含basicHttpBinding、wsHttpBinding、wsDualHttpBinding、webHttpBinding、netTcpBinding、netNamedPipeBinding、netMsmqBinding、netPeerTcpBinding、msmqIntegrationBinding、wsFedrationHttpBinding、ws2007HttpBinding、ws2007FederationHttpBinding等多种绑定。其中不同的绑定支持不同的传输协议,在消息编码、传输安全、通讯方式、安全模式、可靠性会话、事务流方面有着不同的属性,能够满足大部分信息通讯的要求。
绑定类名称传输编码消息版本安全模式可靠性会话事务流BasicHttpBindingHTTP文本SOAP 1.1无不支持不支持WSHttpBindingHTTP文本SOAP 1.2 WS-Addressing 1.0消息禁用WS-AtomicTransactionsWSDualHttpBindingHTTP文本SOAP 1.2 WS-Addressing 1.0消息启用WS-AtomicTransactionsWSFederationHttpBindingHTTP文本SOAP 1.2 WS-Addressing 1.0消息禁用WS-AtomicTransactionsNetTcpBindingTCP二进制SOAP 1.2传输禁用OleTransactionsNetPeerTcpBindingP2P二进制SOAP 1.2传输不支持不支持NetNamedPipesBinding命名管道二进制SOAP 1.2传输不支持OleTransactionsNetMsmqBindingMSMQ二进制SOAP 1.2消息不支持不支持MsmqIntegrationBindingMSMQ不支持不支持传输不支持不支持CustomBinding自定义 自定义 自定义自定义 自定义自定义
二、自定义绑定元素
当预定义的绑定无法满足用户需求时,可以使用CustomBinding类开发自定义绑定,该类存在于System.ServiceModel.Channels命名空间。用户可以根据需要绑定以下属性: 事务(TransactionFlowBindingElement类)、可靠性会话(ReliableSessionBindingElement 类)、安全( SecurityBindingElement 类)、流安全、单工双工工作模式、信息编码、传输绑定等,其中信息编码和传输绑定元素是自定义绑定的必要属性,其他属性用户可根据需求制定。
- 传输绑定元素(必要),用户可选其中一种传输绑定模式。
- 信息编码(必要),用户可以选择其中一种信息编码形式
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 : IExampleService12 {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 33 34 namespace CustomBinding.Client35 {36 class Program37 {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 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 23 <behavior name="defaultBehavior">24 <serviceMetadata httpGetEnabled="true"/>25 behavior>26 serviceBehaviors>27 behaviors>28 <bindings>29 <customBinding>30 31 32 <binding name="customBinding">33 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 34 35 namespace CustomBinding.Client36 {37 class Program38 {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
1 namespace Microsoft.Samples.NetHttpBinding { 2 3 //提供配置节的基类,为NetHttpBindingElement中列举的属性提供预定义绑定 4 public class NetHttpBindingCollectionElement : StandardBindingCollectionElement
注意若需要在通过*.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类设置默认值 [Config�ػ�,���urationProperty(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 set102 {103 if (value != null)104 {105 value.CopyTo(binaryEncoding.ReaderQuotas);106 }107 }108 }109 110 public EnvelopeVersion EnvelopeVersion111 {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 Scheme34 {35 get36 {37 if (securityMode == NetHttpSecurityMode.Transport)38 {39 return httpsTransport.Scheme;40 }41 else42 {43 return httpTransport.Scheme;44 }45 }46 }47 48 //创建当前绑定元素49 public override BindingElementCollection CreateBindingElements()50 { // return collection of BindingElements51 BindingElementCollection bindingElements = new BindingElementCollection();52 bindingElements.Add(binaryEncoding);53 54 if (this.securityMode == NetHttpSecurityMode.Transport)55 {56 bindingElements.Add(this.httpsTransport);57 }58 else59 {60 if (this.securityMode == NetHttpSecurityMode.TransportCredentialOnly)61 {62 this.httpTransport.AuthenticationScheme = AuthenticationSchemes.Negotiate;63 }64 else65 {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中实现。
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 else12 {13 return ProtectionLevel.None;14 }15 }16 }17 18 System.Net.Security.ProtectionLevel ISecurityCapabilities.SupportedResponseProtectionLevel19 {20 get21 {22 if (securityMode == NetHttpSecurityMode.Transport)23 {24 return ProtectionLevel.EncryptAndSign;25 }26 else27 {28 return ProtectionLevel.None;29 }30 }31 }32 33 bool ISecurityCapabilities.SupportsClientAuthentication34 {35 get36 {37 if (securityMode == NetHttpSecurityMode.None)38 {39 return false;40 }41 else42 {43 return true;44 }45 }46 }47 48 bool ISecurityCapabilities.SupportsClientWindowsIdentity49 {50 get51 {52 if (securityMode == NetHttpSecurityMode.None)53 {54 return false;55 }56 else57 {58 return true;59 }60 }61 }62 63 bool ISecurityCapabilities.SupportsServerAuthentication64 {65 get66 {67 if (securityMode == NetHttpSecurityMode.None)68 {69 return false;70 }71 else72 {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 else13 {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 Service11 {12 //设置服务的基础URI13 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 : IEchoService41 {42 #region IEchoService Members43 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 #endregion55 }56 }
在MSDN中已经有此开发实例,在此也不再作详细解释。致此,已经对自定义绑定作出详细的说明,用户可以分别使用代码、配置文件和绑定扩展类三种方式来开发自定义绑定。在使用复杂的面向服务开发系统中实现自定义绑定,可以按照不同的需求实现服务,绑定不同的传输协调,文本传输方式,限制最大传输流量等,不失为实现分布式开发的一种手段。