WCF通道模型
绑定的本质是一个配置好的通道栈,为了方便程序员专著与业务逻辑,WCF提高了一系列常用绑定。随后会有相应的自定义通道栈代码
无论交互的另一方具体位置在哪里,WCF都会为消息的发送和接收建立一个完整的消息管道,这个消息管道也成为通道栈,通道栈中的每一个通道组建,都会有机会对消息进行处理,而整个通道栈是可编辑并且可插入的,这就确保了WCF的通道模型具有相当大的灵活性,WCF通道模型是完全和上层程序隔离的,任何一个服务/客户端都可以轻松地配置到不同的通道模型上去。
通道模型可以被划分为上下两个部分,上面部分的通道被称为协议通道,而下部分的通道称为传输通道,一个通道栈可以拥有任意个协议通道,但一般只拥有一个传输通道,传输通道负责把消息进行编码并且发送到远端,编码时传输通道需要使用通道栈的编码器。
一般而言,协议通道负责维护消息的非业务逻辑功能,这样的功能包括:事务,日志,可靠消息,安全性等,程序员可自定义协议通道并且插入到通道栈中,在一个通道栈中,必须包含至少一个传输通道和编码器,传输通道负责消息的编码和发送,具体到,传输通道会尝试从BindingContext对象查找编码器,如果没有找到则会使用默认的编码器,在完成消息的编码之后,传输通道负责把消息发送到远端,这里不同传输通道将会使用不同的传输协议,例如HTTP,TCP,IPC等
消息交换模式和通道形状
站在消息传输层面,WCF一共支持6种消息交互模式,分别为:数据报模式,请求-相应模式,双工模式,会话数据报模式,会话响应-请求模式和会话双工模式,一个通道可以支持其中一种或几种交互模式,通道通过通道形状,来实现具体的消息交互模式。
所谓通道的形状,指的是定义了发送,接受消息动作的10个接口,他们均继承在IChannel借口,这10 个接口分别为IInputChannel,IOutputChannel,IRequestChannel,IreplyChannel,IDuplexChanel,IInputSessionChannel,IOutputSessionChannel,IRequestSessionChannel,IReplySessionChannel和IDuplexSessionChannel
数据报模式:数据报模式指的是发送端负责把消息发送给对方并且受到确认消息后,就完成消息交互的方式,在这种情况下,发送放唯一能确定的就是消息发送成功,而对于消息是否最终到达服务的终结点,是否成功处理,返回结果如何都一无所知,采用数据报模式的客户段通道实现了IOutputChannel接口,而采用数据报模式的服务端则实现IInputChannel接口。
发送端代码:
static void Main(string[] args) { try { //建立自定义的通道栈 BindingElement[] bindingElements = new BindingElement[3]; bindingElements[0] = new TextMessageEncodingBindingElement();//文本编码 bindingElements[1] = new OneWayBindingElement();//使得传输通道支持数据报模式 bindingElements[2] = new HttpTransportBindingElement();//http传输 CustomBinding binding = new CustomBinding(bindingElements); //创建消息 using (Message message = Message.CreateMessage(binding.MessageVersion, "sendMessage", "Message Body")) { //创建ChannelFactory IChannelFactory<IOutputChannel> factory = binding.BuildChannelFactory<IOutputChannel>(new BindingParameterCollection()); factory.Open(); //创建OutputChannel IOutputChannel outputChannel = factory.CreateChannel(new System.ServiceModel.EndpointAddress("http://localhost:8080/InputService")); outputChannel.Open(); outputChannel.Send(message); Console.WriteLine("已经成功发送消息!"); outputChannel.Close(); factory.Close();//关闭工厂 } } catch (Exception ex) { Console.WriteLine(ex.ToString());//异常输出 } finally { Console.Read(); } }
接收端(服务端)代码:
try { //建立和发送端相同的通道栈 BindingElement[] bindingElements = new BindingElement[3]; bindingElements[0] = new TextMessageEncodingBindingElement();//文本编码 bindingElements[1] = new OneWayBindingElement();//使得传输通道支持数据报模式 bindingElements[2] = new HttpTransportBindingElement();//http传输 CustomBinding binding = new CustomBinding(bindingElements); //创建通道监听器 IChannelListener<IInputChannel> listener = binding.BuildChannelListener<IInputChannel>(new Uri("http://localhost:8080/InputService"), new BindingParameterCollection()); listener.Open(); IInputChannel inputChannel = listener.AcceptChannel(); inputChannel.Open();//打开InputChannel Console.WriteLine("开始接收信息..."); Message message = inputChannel.Receive();//接收信息 Console.WriteLine("接收到一条消息,action为:{0},body为:{1},", message.Headers.Action, message.GetBody<string>()); message.Close(); inputChannel.Close();//关闭通道 listener.Close();//关闭监听器 Console.Read(); } catch (Exception ex) { Console.WriteLine(ex.ToString());//异常输出 } finally { Console.Read(); } }
注意:别忘了引用命名空间 using System.ServiceModel.Channels;并且这是在同一电脑上操作的,至于在局域网或远程接下来会学到,并且分享出来。