从整个基础架构来看 WCF可分为服务模型层和信道层 模型层提供了一个统一的可扩展的编程模型 而信道层提供了对请求信息的接收和处理 而作为WCF通信的三要素之一的绑定 是它实现了组成整个信道层的信道栈 且绑定是联接模型层和信道层的纽带
信道栈
N个信道组成一个信道栈 信道栈就是一个管道 多个管道就组成了一个信道层 信道栈就是用于处理请求的 请求信息进入管道 管道里的信道假设为A、B、C、D 则请求信息会按一定的顺序依次经由A、B、C、D 信道处理 而WCF服务中最基本的信道有以下三个
1.传输信道
2.编码信道
3.协议信道
可以把信道理解成方法 请求或回复的信息进入信道后 由传输信道实现信息的传输与接收 由编码信道对信息进行格式化 由协议信道确保信息传输的安全 其中协议信道是遵循了WS-*协议标准的 WCF的协议信道基于WS-Security实现信息交换的安全性与可靠性 WS-*协议是一个所有web服务墨守的准则 各种平台开发的服务只要基于这个标准 就可以实现服务的跨平台 总结一下就是 绑定>信道层>信道栈>信道
通过绑定实现信息传输与接收
信道栈是绑定所持有的 但它并不是绑定唯一拥有的成员 它还具有一些其它的成员 我们下面通过一个实例来实现消息传输与接收从而引出绑定所持有的其它成员对象和信道栈 既然信道栈提供了三个基本的信道 那么我们可以利用它来显示的实现信息传输与信息接收
创建两个项目
ServerModel(服务端)和ClientModel(客户端)两个项目都引用System.ServiceModel
先实现服务端的侦听 如果侦听到请求就回复
1 using System.ServiceModel; 2 using System.ServiceModel.Channels; 3 using System.Xml.Linq; 4 5 static void Main(string[] args) 6 { 7 Uri uri = new Uri("http://127.0.0.1:9999/Listener"); 8 //创建绑定 9 Binding binding = new BasicHttpBinding(); 10 //用绑定创建信道侦听器之回复信道IReplyChannel 11 IChannelListener<IReplyChannel> channelListener = binding.BuildChannelListener<IReplyChannel>(uri); 12 //开启侦听器 13 channelListener.Open(); 14 //创建回复信道 15 IReplyChannel replyChanel = channelListener.AcceptChannel(TimeSpan.MaxValue); 16 //开启回复信道 17 replyChanel.Open(); 18 //侦听开始 19 while (true) 20 { 21 //回复信道接收来自客户端的请求上下文 同时指定接收请求上下文的超时时限 22 RequestContext context = replyChanel.ReceiveRequest(TimeSpan.MaxValue); 23 //输出接收到的请求的信息 24 Console.WriteLine(context.RequestMessage); 25 //回复信道回复客户端 26 string action = "http://www.artech.com/calculatorservice/AddResponse"; 27 XNamespace ns = "http://www.artech.com"; 28 XElement body = new XElement(new XElement(ns + "AddResponse", new XElement(ns + "AddRresult", 3))); 29 Message msg= Message.CreateMessage(binding.MessageVersion, action, body); 30 context.Reply(msg); 31 } 32 }
接着实现客户端发送请求并接收服务端回复信息
1 using System.ServiceModel; 2 using System.ServiceModel.Channels; 3 using System.Xml.Linq; 4 5 static void Main(string[] args) 6 { 7 Uri uri = new Uri("http://127.0.0.1:9999/Listener"); 8 //创建绑定 9 Binding binding = new BasicHttpBinding(); 10 //用绑定创建信道工厂 11 IChannelFactory<IRequestChannel> channelFactory = binding.BuildChannelFactory<IRequestChannel>(); 12 //开启信道工厂 13 channelFactory.Open(); 14 //创建请求信道 15 IRequestChannel channel = channelFactory.CreateChannel(new EndpointAddress(uri)); 16 //开启请求信道 17 channel.Open(); 18 //创建请求的信息 19 string action = "http://www.artech.com/calculatorservice/Add"; 20 XNamespace ns = "http://www.artech.com"; 21 XElement body = new XElement(new XElement(ns + "Add", new XElement(ns + "x", 1), new XElement(ns + "y", 2))); 22 Message msg = Message.CreateMessage(binding.MessageVersion,action,body); 23 //发送请求后接收回复 24 Message replyMsg = channel.Request(msg); 25 Console.WriteLine(replyMsg); 26 Console.Read(); 27 }
服务端接收到的请求如下
客户端接收到的回复如下
信道管理器
在例子中信道侦听器IChannelListener<IReplyChannel>和信道工厂IChannelFactory<IRequestChannel>都继承自信道管理器ChannelManagerBase 所以我们也可以说信道侦听器和信道工厂是一个信道管理器 由它们来全权负责创建有具体功能的信道(Channel)信道实现了处理信息的能力 它们都是由信道管理器创建的 而信道管理器用于服务时使用的是信道侦听器 用于请求时使用的是信道工厂 而信道栈是由绑定创建的 在例子中可以看到 服务端我们使用了BasicHttpBinding来创建信道管理器(侦听器)而在客户端使用BasicHttpBinding创建信道管理器(信道工厂) 信道管理器是泛型类型 接收一个具体的信道类型来初始化它 比如信道侦听器IChannelListener<TChannel>中的TChannel可以是任何具体的信道类型 信道工厂IChannelFactory<TChannel>也是如此 通过指定具体的信道类型初始化信道管理器 如
1 Uri uri = new Uri("http://127.0.0.1:9999/Listener"); 2 Binding binding = new BasicHttpBinding(); 3 IChannelListener<IReplyChannel> channelListener = binding.BuildChannelListener<IReplyChannel>(uri);//使用绑定创建信道管理器并指定了信道管理器拥有的成员IReplyChannel信道接着就可以使用信道管理器的方法来创建具体的信道(按创建管理器时指定的信道类型) 4 IReplyChannel replyChanel = channelListener.AcceptChannel(TimeSpan.MaxValue);
通信对象
信道管理器 信道实际上都是用于处理消息的 所以说它们同时也是通信对象 WCF中 为这些与通信相关的类定义了一个统一的ICommunicationObject 该接口定义了5个事件 7个方法 1个表示通信状态的枚举
5个事件:Opening(开启前)Opened(开启后)Closing(关闭前)Closed(关闭后)Faulted(出错时)
7个方法:Open(开启)BeginOpen(异步开启)EndOpen(完成异步操作后开启)Close(关闭)BeginClose(异步关闭)EndClose(完成异步操作后关闭)Abort(立即终止)
1个枚举:State属性是一个CommunicationState 可能的值有 Created(已创建)Opening(正在开启)Opened(已开启)Closing(正在关闭)Closed(已关闭)Faulted(出错)
实现了ICommunicationObject接口的是一个CommunicationObject类 而所有的信道或信道管理器都间接或直接派生于CommunicationObject
通信超时
较之一般的方法调用 与通信相关的方法则需要耗费一定的时间 一个用于通信的方法在一段时间内如果还没有返回结果就应该终止它而不是无条件的等下去 所以超时处理通信显得尤为重要 默认情况下WCF为通信对象(即信道或信道管理器)设置了默认的超时时间(IDefaultCommunicationTimeOut) 你也可以在创建通信对象时 设一个自定义的超时时间
信息交换模式
MEP(Message Exchange Pattern)在SOA中时一个重要的概念 典型的MEP又以下几种
数据报模式 (DataGram)
此为最简单的信息交换模式 因为它只是单向传输 从一个源发出信息到一个(单投)或多个地址(多投/广播) 即发送方发送信息到一个或多个接收方去 但发送方并不实现接收
请求-回复模式 (Request-Reply)
使用最多的一种模式 客户端向服务端发送请求并等待接收服务端回复的请求 服务端等待接收客户端请求并回复客户端
双工模式(Duplex)
客户端和服务器端的角色是可以互换的 在Request-Reply模式中 服务器端一般可能仅仅提供回复服务 它并不需要主动地联系客户端做什么 但在双工模式下服务端可以主动地联系客户端进行一些操作 而基于TCP协议的请求 本身就是一个全双工的的网络协议 所以能够提供双工模式的全面支持 但是对于HTTP/HTTPS 它本身是一个Request-Reply的简单通信模式 如果要实现基于HTTP/HTTPS的双工通信模式 则需要使用WSDualHttpBinding
信道基类
WCF提供了一个IChannel接口和一个ChannelBase抽象类来表示信道
IChannel接口
每一种形态的信道都间接或直接实现了IChannel接口 该接口只提供了一个属性GetProperty<T>来获取指定类型的属性
ChannelBase抽象类
此类实现了IChannel接口、ICommunicationObject接口、IDefaultCommunicationTimeouts接口和CommunicationObjec类
信道形态之普通信道
信道形态用于规范在某种通信模式中 发送端和接收端所使用的信道类型 WCF定义了统一的接口来定义在不同的通信模式下信息发送方和信息接收方所使用的信道的不同作用 这些作用通过以下接口来表示 他们都实现了IChannel接口
在数据报模式下 信息发送方的信道行为必须是:IOutputChannel 信息接收方的信道行为必须是:IInputChannel
在请求-回复模式下 请求信息方的信道行为必须是:IRequestChannel 回复信息方的信道行为必须是:IReplyChannel
在双工模式下 信息发送方的信道行为必须是:IDuplexChannel 信息接收方的信道行为必须是:IDuplexChannel IDuplexChannel同时实现了IOutputChannel 和IInputChannel
这些关于信道形态的接口都实现了IChannel接口 而ChannelBase(信道抽象基类)也实现了IChannel接口
如此 根据不同的通信模式 我们就要创建对应的信道(信道形态其实就是信道 只是需要根据不同的通信模式来创建对应的信道)比如前面的实现通信的例子中 客户端要发送请求道服务端 服务端将恢复客户端的请求 这是一个典型的Request-Reply模式 所以在客户端 我们创建信道时 使用的是IRequestChannel 如下:
1 Uri uri = new Uri("http://127.0.0.1:9999/Listener"); 2 //创建绑定 3 Binding binding = new BasicHttpBinding(); 4 //用绑定创建信道管理器 在客户端信道管理器应为信道工厂 所以这里创建信道工厂对象 同时要指定信道形态
//这是一个典型的Request-Reply的通信模式 而此处是客户端 所以将IRequestChannel形态的信道放进信道控制器里 以便后面创建它 5 IChannelFactory<IRequestChannel> channelFactory = binding.BuildChannelFactory<IRequestChannel>(); 6 //开启信道工厂 7 channelFactory.Open(); 8 //创建Request-Reply模式下的请求形态的信道 9 IRequestChannel channel = channelFactory.CreateChannel(new EndpointAddress(uri));
而在服务端 根据Request-Reply模式 我们创建信道时 使用的是IReplyChannel
1 Uri uri = new Uri("http://127.0.0.1:9999/Listener"); 2 //创建绑定 3 Binding binding = new BasicHttpBinding(); 4 //用绑定创建信道管理器 在服务端信道管理器应为信道侦听器 所以这里创建信道侦听器对象 同时要指定信道形态
//这是一个典型的Request-Reply的通信模式 而此处是服务端 所以将IReplyChannel形态的信道放进信道控制器里 以便后面创建它 5 IChannelListener<IReplyChannel> channelListener = binding.BuildChannelListener<IReplyChannel>(uri); 6 //开启侦听器 7 channelListener.Open(); 8 //创建回复信道 9 IReplyChannel replyChanel = channelListener.AcceptChannel(TimeSpan.MaxValue);
数据报模式下发送方使用的信道IOutputChannel类
该类有3个方法用于发送信息 2个属性表示信息发送的逻辑地址和物理地址
3个方法 Send(发送)BeginSend(开始异步发送)EndSend(异步完成后发送)
2个属性 RemoteAddress(逻辑地址)Via(物理地址)
数据报模式下接收方使用的信道IInputChannel类
与IOutputChannel类相反 IInputChannel类实现信息的接收 它有9个方法用于接收信息 1个属性表示本地终结点地址
9个方法 Receive(接收)BeginReceive(异步接收)EndReceive(异步完成后接收)TryReceive(在给定的时间内尝试接收)BeginTryReceive(同前)EndTryReceive(同前)WaitForMessage(检测是否有信息抵达)BeginWaitForMessage(同前)EndWaitForMessage(同前)
1个属性 LocalAddress 该属性是一个EndPointAddress类
请求-回复模式下请求方使用的信道IRequestChannel 类
该类有3个方法用于发送信息同时接收回复信息 2个属性表示信息发送的逻辑地址和物理地址
3个方法 Request(发送信息并接收回复信息)BeginRequest(异步发送信息并接收回复信息)EndRequest(异步完成后发送信息并接收回复信息)
2个属性 RemoteAddress(逻辑地址)Via(物理地址)
请求-回复模式下回复方使用的信道IReplyChannel类
IReplyChannel类实现信息的接收与回复 它有9个方法用于接收信息 1个属性表示本地终结点地址
9个方法ReceiveRequest(接收)BeginReceiveRequest(异步接收)EndReceiveRequest(异步完成后接收)TryReceiveRequest(在给定的时间内尝试接收)BeginTryReceiveRequest(同前)EndTryReceiveRequest(同前)WaitForRequest(检测是否有信息抵达)BeginWaitForRequest(同前)EndWaitForRequest(同前)
1个属性 LocalAddress 该属性是一个EndPointAddress类
注意:无论是ReceiveRequest还是TryReceiveRequest 包括异步版本的方法 它们都是返回一个System.ServiceModel.Channels.RequestContext类型的上下文对象 此对象可以看做是客户端与服务端的一座桥梁 ReceiveRequest直接返回该对象 而TryReceiveRequest将该对象作为输出参数返回 此对象承上启下 使用它可以获取完整的请求信息(RequestContext.RequestMessage)还可以使用它发送回复信息给请求者(RequestContext.Reply | BeginReply)
双工模式下使用的信道IDuplexChannel类
由于双工模式中发送方与接收方具有完全一样的信道形态 所以它同时实现了IOutputChannel和IInputChannel接口 可以直接调用IOutputChannel和IInputChannel类的方法
信道形态之会话信道
会话信道的作用是将客户端与服务端的通信生成一个ID 请求信息与会话ID关联在一起 则服务端就知道请求是源自哪个客户端 会话信道的除了拥有普通信道的功能 它还独有保持客户端与服务端会话状态的功能 根据不同的需求 你可以创建普通的信道(如IRequestChannel、IReplyChannel、IOutputChannel、IInputChannel、IDuplexChannel)或者创建会话信道 会话信道基接口为ISession 它规定了一个ID属性来标识客户端会话 实现了ISession接口的接口有IOutputSession、IInputSession和IDuplexSession 对于不同的信息模式下的通信 会话信道有对应的类来表示 数据报模式下的会话信道为:IOutputSessionChannel和IInputSessionChannel 请求-回复模式下的会话信道为:IRequestSessionChannel、IReplySessionChannel 双工模式下的会话信道为:IDuplexSessionChannel 这些会话信道类间接或直接派生于ISessionChannel<TSession> 泛型参数TSession实现了ISession接口 如下
IRequestSessionChannel派生于ISessionChannel<IOutputSession>、IReplySessionChannel派生于ISessionChannel<IInputSession>、IOutputSessionChannel派生于ISessionChannel<IOutputSession>、IInputSessionChannel派生于ISessionChannel<IInputSession> 、IDuplexSessionChannel派生于ISessionChannel<IDuplexSession>
信道管理器之信道侦听器
信道侦听器就是服务于服务端的 实现了IChannelListener和IChannelListener<TChannel>接口 前一个用于检测信道的状态 后一个用于创建信道 另外还有两个信道侦听器类 IChannelListenerBase和 IChannelListenerBase<TChannel> 前一个类实现IChannelListener接口 而后一个派生于前一个类且实现IChannelListener<TChannel>接口 是代表侦听器所有实现的基类
IChannelListener接口
IChannelListener接口提供了以下方法用于检测信道(栈) 这几个方法会试图获取一个信道(栈)或使用IChannelListener<TChannel>创建一个新的信道(栈) 如果在规定的时限内获取或创建信道(栈)成功则返回true 否则返回false
WaitForChannel(检测)
BeginWaitForChannel(异步检测)
EndWaitForChannel(异步完成后检测)
该接口还提供了GetProperty<T>来获取指定类型的属性、Uri获取侦听的地址
IChannelListener<TChannel>接口
该接口实现了IChannelListener接口 其中泛型参数TChannel实现了IChannel接口 它表示信道侦听器将创建基于某种信道形状(TChannel)的信道 提供了以下几个方法方法用于创建信道栈来处理请求信息
AccpChannel(获取或创建信道)
BeginAccpChannel(异步获取或创建)
EndAccpChannel(异步完成后获取或创建)
IChannelListenerBase抽象类
该类实现了IChannelListener接口
IChannelListenerBase<TChannel>抽象类
该类派生于IChannelListenerBase类且实现了IChannelListener<TChannel>接口 如果需要扩展信道侦听器 则可以继承 IChannelListenerBase<TChannel> 因为它包含了所有用于信道侦听器的实现 即上面介绍的两个接口和一个基类都被IChannelListenerBase<TChannel>继承或实现了 他们提供的所有方法属性等操作 都可以通过IChannelListenerBase<TChannel>来获取
信道管理器之信道工厂
信道工厂服务于客户端 用于发送请求和接收服务端的回复 信道工厂实现了IChannelFactoy和IChannelFactory<TChannel>接口 两个接口前一个用于获取信道属性 后一个用于创建信道 还有两个信道工厂类 ChannelFactoryBase和ChannelFactoryBase<TChannel> 前一个实现了IChannelFactoy接口 后一个实现了IChannelFactory<TChannel>接口且派生于前一个类 即 ChannelFactoryBase<TChannel>是代表信道工厂所有实现的基类
IChannelFactoy接口
只提供了一个属性用于GetProperty<T>来获取指定类型的属性
IChannelFactory<TChannel>接口
只提供了一个方法CreateChannel用于创建基于TChannel形态的信道
ChannelFactoryBase抽象类
实现了IChannelFactoy接口
ChannelFactoryBase<TChannel> 抽象类
派生于ChannelFactoryBase类且实现了IChannelFactory<TChannel>接口 如果需要扩展信道工厂 则可以继承 ChannelFactoryBase<TChannel> 因为它包含了所有用于信道工厂的实现 即上面介绍的两个接口和一个基类都被ChannelFactoryBase<TChannel>继承或实现了 他们提供的所有方法属性等操作 都可以通过ChannelFactoryBase<TChannel>来获取
信道管理器的两种创建方式
信道管理器有两种模式 一是基于普通信道的信道管理器 二是基于会话信道的信道管理器 普通信道不会保持两端的会话 而会话信道会保持两端会话 即在会话信道模式下的信道管理器在服务端不是共享的 服务端为每一个到达的请求生成ID 它被专门用于处理来自ID为xxx的客户端的后续请求 总结一下就是在普通信道模式下 服务端的一个信道栈处理N个客户端的请求 而在会话模式下 服务端的一个信道栈专门处理一个客户端的请求
绑定对象
多个绑定元素组成了一个绑定对象 绑定对象的特性与能力是由绑定元素及绑定元素的先后次序决定的 虽然不是每种类型的绑定元素都会创建相应的信道管理器 但是所有的信道管理器都是通过绑定元素来创建的 即绑定元素最根本的作用的就是实现信道管理器的创建(信道侦听器和信道工厂)
BindingElement抽象类
WCF使用BindingElement来表示绑定元素 如果要扩展绑定元素 则可以考虑继承此类 此类提供以下四个重要的方法
BuildChannelListener<TChannel>
用于创建基于信道形态的信道侦听器 接收一个绑定上下文对象(BindingContext )
BuildChannelFactory<TChannel>
用于创建基于信道形态的信道工厂 接收一个绑定上下文对象(BindingContext )
CanBuildChannelListener<TChannel>
我们前面说 绑定元素不全是用于创建信道管理器的 某些类型的绑定元素并不创建信道管理器 所以BindingElement类提供此方法来测试当前绑定元素是否具有创建信道管理器的能力
CanBuildChannelFactory<TChannel>
同上
Binding抽象类
WCF使用Binding类来表示绑定对象 不同类型的绑定对象都间接或直接继承自此类 Binding类重要方法如下
CreateBindingElement
该方法用于创建绑定元素 返回一组绑定元素集合(BindingElementCollection)
BuildChannelFactory<TChannel>
与BindingElement的同名方法不一样 该方法用于创建基于信道形态的信道工厂通道 并返回一个位于信道栈最顶层的信道工厂
BuildChannelListener<TChannel>
与BindingElement的同名方法不一样 该方法用于创建基于信道形态的信道侦听器通道 并返回一个位于信道栈最顶层的信道侦听器
CanBuildChannelListener<TChannel>
测试当前绑定对象是否具有创建信道管理器的能力
CanBuildChannelFactory<TChannel>
同上
BindingContext类
表示绑定上下文对象
Binding属性
表示创建了当前上下文对象的绑定对象
RemainingBindingElements属性
表示创建了当前上下文对象的绑定对象的绑定元素集合(BindingElementCollection)
BindingParameters属性
该属性是一个BindingParameterCollection集合 用于控制信道的行为
BuildInnerChannelListener<TChannel>方法
循环获取创建了当前上下文对象的绑定对象的绑定元素集合 并按照元素在集合中的排列顺序依次调用它们的BuildChannelListener<TChannel>方法来创建与绑定元素对应的信道侦听器
BuildInnerChannelFactory<TChannel>方法
循环获取创建了当前上下文对象的绑定对象的绑定元素集合 并按照元素在集合中的排列顺序依次调用它们的BuildChannelListener<TChannel>方法来创建与绑定元素对应的信道工厂
绑定元素创建信道管理器流程
我们通过WsHttpBinding这个绑定对象来说明整个创建流程 WsHttpBinding是一个绑定对象 它由HttpTransportBindingElement(传输元素)和TextMessageEncodingBindingElement(编码元素)两个绑定元素组成 当使用WsHttpBinding创建信道侦听器通道时 WsHttpBinding首先会调用BindingContext创建一个绑定上下文对象 BindingContext随后调用自身的BuildInnerChannelListener<TChannel>方法 该方法会循环获取RemainingBindingElements属性 每一次获取一个绑定元素 并调用这个绑定元素对应的BuildChannelListener<TChannel>来创建信道侦听器同时从RemainingBindingElements绑定元素集合中移除这个元素 而第一个信道侦听器创建时又会调用BindingContext的BuildInnerChannelListener<TChannel>方法 以此类推直到结束 所以 所有在绑定元素集合中的元素依次按顺序都会被调用 而由这些绑定元素创建的一个个的信道侦听器也会按照绑定元素的排列次序联合组成一个信道侦听器通道 而信道工厂的创建方式与创建信道侦听器完全一样
系统绑定
WCF预定义了一系列的系统绑定 如下
BasicHttpBinding
WSHttpBinding
WS2007HttpBinding
WSDualHttpBinding
实现了基于HTTP的双向通信 因为原生的HTTP通信仅支持单向的信息传送通道 而WSDualHttpBinding它是创建了两个关联的HTTP通道来实现所谓的双向通信 该绑定基本上用于局域网环境
NetTcpBinding
传输方式为TCP 它采用TCP协议对双工通信实现了原生的支持
NetNamedPipeBinding
传输方式为命名管道
NetMsmqBinding
传输方式为消息队列
其中以Net为前缀的绑定对象局限于.Net平台使用 即客户端和服务端都必须是.Net的WCF程序 这种应用场景通常用于局域网中 所以可以统称为局域网绑定 而以WS为前缀的绑定对象提供了对服务标准协议WS-*的全面支持 所以以WS为前缀的绑定是跨平台的 参看详细http://www.cnblogs.com/artech/archive/2008/12/14/1354691.html
绑定配置
使用默认绑定类型
在配置文件中代表绑定类型集合的节点为Bindings节 默认绑定类型即系统绑定类型 如前所述 如
1 <system.serviceModel> 2 3 <bindings> 4 <ws2007HttpBinding> 5 <binding name="firstBinding" allowCookies="true" messageEncoding="Text"> 6 <reliableSession enabled="true"/> 7 <security mode="Transport"/> 8 </binding> 9 </ws2007HttpBinding> 10 </bindings> 11 12 <services> 13 <service name="Service.CalculatorService"> 14 <endpoint address="http://127.0.0.1:7777/calculatorservice" binding="ws2007HttpBinding" bindingConfiguration="firstBinding" 15 contract="Service.Interface.ICalculator"/> 16 </service> 17 </services> 18 19 </system.serviceModel>
在Bindings节中配置绑定类型 如例子中配置了一个ws2007HttpBinding的绑定类型 接着在绑定类型中使用binding节表示绑定对象 该节的子节就是N个绑定元素
使用自定义的绑定类型
还可以使用自定义的绑定类型 自定义绑定类型使用customBinding节表示 如
1 <system.serviceModel> 2 3 <bindings> 4 5 <ws2007HttpBinding> 6 <binding name="firstBinding" allowCookies="true" messageEncoding="Text"> 7 <reliableSession enabled="true"/> 8 <security mode="Transport"/> 9 </binding> 10 </ws2007HttpBinding> 11 12 <customBinding> 13 <binding name="firstBinding"> 14 <reliableSession flowControlEnabled="true"/> 15 <mtomMessageEncoding messageVersion="Soap12WSAddressing1.0"/> 16 <tcpTransport/> 17 </binding> 18 </customBinding> 19 20 </bindings> 21 22 <services> 23 <service name="Service.CalculatorService"> 24 <endpoint address="http://127.0.0.1/service" binding="ws2007HttpBinding" bindingConfiguration="firstBinding" contract="Service.Interface.ICalculator" /> 25 <endpoint address="http://127.0.0.1/service" binding="customBinding" bindingConfiguration="firstBinding" contract="Service.Interface.ICalculator" /> 26 </service> 27 </services> 28 29 </system.serviceModel>
使用自定义的绑定元素
要使用自定义的绑定元素 前提是要定义一个类来继承配置元素抽象基类(BindingElementExtentionElement) 重写其中的两个方法 BindingElementType(返回绑定元素的类型)和CreateBindingElement(创建绑定元素) 在我们上一篇文章中的自定义绑定的项目Custom中添加一个新类SimpleSessionBindingElementExtentionElement
1 using System.ServiceModel.Channels; 2 3 namespace Custom 4 { 5 public class SimpleSessionBindingElementExtentionElement:SimpleSessionBindingElementExtensionElement 6 { 7 public override Type BindingElementType 8 { 9 get 10 { 11 return typeof(SimpleSessionBindingElement); 12 } 13 } 14 15 protected override BindingElement CreateBindingElement() 16 { 17 return new SimpleSessionBindingElement(); 18 } 19 20 } 21 }
接着就可以在配置中通过extensions的bindingElementExtensions来添加一个绑定元素
1 <system.serviceModel> 2 3 <bindings> 4 <customBinding> 5 <binding name="myBinding"> 6 <textMessageEncoding /> 7 <myExBinding /> 8 <tcpTransport /> 9 </binding> 10 </customBinding> 11 </bindings> 12 13 <extensions> 14 <bindingElementExtensions> 15 <add name="myExBinding" 16 type="Custom.SimpleSessionBindingElementExtensionElement, Service.Interface, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/> 17 </bindingElementExtensions> 18 </extensions> 19 20 <services> 21 <service name="Service.CalculatorService"> 22 <endpoint address="http://127.0.0.1/service" binding="customBinding" 23 bindingConfiguration="myBinding" contract="Service.Interface.ICalculator" /> 24 </service> 25 </services> 26 27 </system.serviceModel>