WCF中的终结点(ServiceEndpoint)包含有三要素:地址(EndpointAddress),绑定(Binding),契约描述(ContractDescription)三要素;其中绑定的在整个WCF体系架构中具有重要的作用,绑定决定了服务之间通信的模式以及消息中特殊处理;
WCF体系中分为服务模型层和信道层,信道层就是通过绑定来进行创建的;
绑定(Binding)
在WCF中默认定义了许多种的绑定;
类型名 | 配置文件使用名 | 描述 |
BasicHttpBinding | basicHttpBinding | 用于和早期的webservice相兼容 |
WSHttpBinding | wsHttpBinding | web服务绑定,支持最新的web服务标准WS* |
WSDualHttpBinding | wsDualHttpBinding | 支持WS*和双向通信 |
WSFederationHttpBinding | wsFederationHttpBinding | 支持WS* ,设计到单点登录的安全相关 |
NetNamedPipeBinding | netNamedPipeBinding | 面向连接的绑定,在一台机器上用命名管线通信 |
NetTcpBinding | netTcpBinding | 面向连接的绑定,通过Tcp进行跨进程和机器的通信 |
NetPeerTcpBinding | netPeerTcpBinding | 支持端到端的通信 |
NetMsmqBinding | netMsmqBinding | 支持基于MSMQ的通信 |
MsmqIntegrationBinding | msmqIntegrationBinding | 支持MSMQ组件的迁移 |
在WCF系统的默认绑定中,以Net为前缀的局限于.NET平台使用;在这些绑定种都继承了System.ServiceModel.Channels.Binding这个抽象类;在Binding类中定义了创建信道监视器的的方法(BuildChannelListener)以及创建信道工厂的方法(BuildChannelFactory),抽象方法CreateBindingElements时创建绑定元素集合;
在这个绑定生成信道层的创建过程是调用Binding 中CreateBindingElements方法来创建绑定元素集合,每一种绑定元素创建信道监视器(IChannelListener)或是信道工厂(IChannelFactory),信道监视器或是信道工厂来创建相应的信道;
IChannel
public interface IChannel : ICommunicationObject { T GetProperty<T>() where T : class; }
在WCF的绑定体系中,所有的信道对象都要实现 System.ServiceModel.Channels.IChannel接口,在IChannel 接口中只有一个GetProperty<T>方法,这个方法时从通道堆栈中返回请求类型的对应;通过这个方法可以获取信道是否具有某终能力或特性; 在WCF绑定体系中System.ServiceModel.Channels.ChannelBase 继承了IChannel 接口,并实现了IChannel 接口的GetProperty<T>方法;
public abstract class ChannelBase :IChannel { protected ChannelBase(ChannelManagerBase channelManager) { this.channelManager = channelManager; } public virtual T GetProperty<T>() where T : class { IChannelFactory channelManager = this.channelManager as IChannelFactory; if (channelManager != null) { return channelManager.GetProperty<T>(); } IChannelListener listener = this.channelManager as IChannelListener; if (listener != null) { return listener.GetProperty<T>(); } return default(T); } }
System.ServiceModel.Channels.ChannelManagerBase类中是信道工厂和信道监视器的基类;
public abstract class ChannelFactoryBase : ChannelManagerBase, IChannelFactory, ICommunicationObject public abstract class ChannelListenerBase : ChannelManagerBase, IChannelListener, ICommunicationObject
在 ChannelBase 抽象类中GetProperty方法内部将转换为获取IChannelFactory或是IChannelListener接口中的GetProperty方法;
比如在BasicHttpBinding绑定种创建的监听器内部类HttpChannelListener中实现了GetProperty方法;
internal abstract class HttpChannelListener : TransportChannelListener { public override T GetProperty<T>() where T: class { if (typeof(T) == typeof(EndpointIdentity)) { return (T) this.identity; } if (typeof(T) == typeof(ILogonTokenCacheManager)) { object identityModelProperty = this.GetIdentityModelProperty<T>(); if (identityModelProperty != null) { return (T) identityModelProperty; } } else { if (typeof(T) == typeof(ISecurityCapabilities)) { return (T) this.securityCapabilities; } if (typeof(T) == typeof(System.Security.Authentication.ExtendedProtection.ExtendedProtectionPolicy)) { return (T) this.extendedProtectionPolicy; } } return base.GetProperty<T>(); } }
信道形状
WCF信道形状表示不同的消息交换模式对消息交换双方信道的不同要求,并定义了相应的接口来规范基于不同信道形状的信道应该具有的操作;WCF是通过消息来进行数据的交换,在消息交换模式下就分为数据报模式,请求回复模式以及双工模式;
数据报模式
数据报模式就是单向模式,分为消息接收方以及消息接收方,消息发送方将消息发送给消息接收方,并不需要得到对方的回复或是应答;对于消息发送方不在乎消息接收方式一个还是多个,因此可以支持广播模式;
对于数据报模式反映在WCF体系中,对于消息发送方就是输出数据报,消息接收方就是输入数据报;WCF在System.ServiceModel.Channels命名空间下定义了IInputChannel/IOutputChannel接口来支持单向模式;
对应消息的发送方就必须支持IOutputChannel接口
public interface IOutputChannel : IChannel, ICommunicationObject { IAsyncResult BeginSend(Message message, AsyncCallback callback, object state); IAsyncResult BeginSend(Message message, TimeSpan timeout, AsyncCallback callback, object state); void EndSend(IAsyncResult result); void Send(Message message); void Send(Message message, TimeSpan timeout); EndpointAddress RemoteAddress { get; } Uri Via { get; } }
在IOutputChannel接口中Send方法就是发送数据报的方法,参数Message就是需要发送给消息接收端的消息内容,在send方法可以看到返回参数是void,因此可以看出send方法时不需要消息接收端在接收到消息后给出应答或是回应的;而且在接口中也提高了send方法的异步方法BeginSend/EndSend ;而且也提供了EndpointAddress 和 Uri 这2个属性;EndpointAddress 对应的是终结点的逻辑地址而Uri 是终结点的监听地址;
对于消息的接收方必须支持IInputChannel接口
public interface IInputChannel : IChannel, ICommunicationObject { IAsyncResult BeginReceive(AsyncCallback callback, object state); IAsyncResult BeginReceive(TimeSpan timeout, AsyncCallback callback, object state); IAsyncResult BeginTryReceive(TimeSpan timeout, AsyncCallback callback, object state); IAsyncResult BeginWaitForMessage(TimeSpan timeout, AsyncCallback callback, object state); Message EndReceive(IAsyncResult result); bool EndTryReceive(IAsyncResult result, out Message message); bool EndWaitForMessage(IAsyncResult result); Message Receive(); Message Receive(TimeSpan timeout); bool TryReceive(TimeSpan timeout, out Message message); bool WaitForMessage(TimeSpan timeout); EndpointAddress LocalAddress { get; } }
IInputChannel接口中的Receive方法就是对于消息发送方发送的消息进行消息的接收,方法的返回参数Message 就是消息发送方发送的消息;而且也提供了Receive方法的异步方法BeginReceive/EndReceive;在IInputChannel接口中还提供了TryReceive与WaitForMessage方法;TryReceive方法用于在一个给定时间内尝试去接收消息请求,而WaitForMessage方法用于检测是否有消息抵达;
请求-回复/应答模式
请求-回复模式是指消息的发送方发送消息后,需要得到消息接收方接收消息后给予应答; 最常见的一种例子就是在浏览器中请求一个服务器,期望得到服务器的回复;
对于请求-回复/应答模式反映在WCF体系中,对于消息发送方就是消息的请求方,消息接收方就是消息的回复/应答方;WCF在System.ServiceModel.Channels命名空间下定义了 IRequestChannel/IReplyChannel接口来支持请求-回复/应答模式;
对应是消息的请求方就必须支持IRequestChannel接口
public interface IRequestChannel : IChannel, ICommunicationObject { IAsyncResult BeginRequest(Message message, AsyncCallback callback, object state); IAsyncResult BeginRequest(Message message, TimeSpan timeout, AsyncCallback callback, object state); Message EndRequest(IAsyncResult result); Message Request(Message message); Message Request(Message message, TimeSpan timeout); EndpointAddress RemoteAddress { [__DynamicallyInvokable] get; } Uri Via { get; } }
IRequestChannel接口中的Request方法就是消息的请求方法,参数Message为消息发送方的发送的消息,而返回值Message为消息接收方返回的消息;并且提供了异步的方法BeginRequest/EndRequest;
对于消息的回复/应答方必须支持IReplyChannel接口
public interface IReplyChannel : IChannel, ICommunicationObject { IAsyncResult BeginReceiveRequest(AsyncCallback callback, object state); IAsyncResult BeginReceiveRequest(TimeSpan timeout, AsyncCallback callback, object state); IAsyncResult BeginTryReceiveRequest(TimeSpan timeout, AsyncCallback callback, object state); IAsyncResult BeginWaitForRequest(TimeSpan timeout, AsyncCallback callback, object state); RequestContext EndReceiveRequest(IAsyncResult result); bool EndTryReceiveRequest(IAsyncResult result, out RequestContext context); bool EndWaitForRequest(IAsyncResult result); RequestContext ReceiveRequest(); RequestContext ReceiveRequest(TimeSpan timeout); bool TryReceiveRequest(TimeSpan timeout, out RequestContext context); bool WaitForRequest(TimeSpan timeout); EndpointAddress LocalAddress { get; } }
IReplyChannel接口中的ReceiveRequest方法开始对消息进行接收,返回值为RequestContext 类型,这是个包装了请求的上下文,在这个上下文中包装了请求的消息(RequestContext的Message RequestMessage 属性),可以调用RequestContext 的Reply方法来进行消息的回复;
public abstract class RequestContext : IDisposable { protected RequestContext(); public abstract Message RequestMessage { get; } public abstract IAsyncResult BeginReply(Message message, AsyncCallback callback, object state); public abstract IAsyncResult BeginReply(Message message, TimeSpan timeout, AsyncCallback callback, object state); public abstract void EndReply(IAsyncResult result); // // 摘要: 在派生类中重写时,答复请求消息。 // 参数: message: 包含请求的传入 System.ServiceModel.Channels.Message。 public abstract void Reply(Message message); public abstract void Reply(Message message, TimeSpan timeout); }
双工模式
在双工模式下进行消息交换的双方都可以向对方发送消息,也就是在服务端可以回调客户端的方法;
在WCF中对于双工反应在IDuplexChannel接口上,IDuplexChannel接口继承了IInputChannel/IOutputChannel接口,双工信道具备消息方法和接收的两种功能;
public interface IDuplexChannel : IInputChannel, IOutputChannel, IChannel, ICommunicationObject { }
会话通道
会话是两个终结点之间消息交换的一种相互关系,一个服务是否支持话是通过服务契约中的SessionMode属性指定,SessionMode属性包括:
Allowed 如果绑定支持会话,则契约支持会话
Required 要求绑定支持会话,否则引发异常
NotAllowed 指定契约不支持启动会话的绑定
如果一个服务支持会话,则相关的信道要提供会话的支持,在WCF信道体系中通过System.ServiceModel.Channels命名空间下的ISession接口来实现,在ISession接口中只有一个ID的字符串类型的属性,这个ID是唯一性的标识,请求的消息如果与会话ID相关联,就知道了它是来源自哪个客户端的请求;
public interface ISession { string Id { get; } }
对于支持会话的通道,WCF提供了支持Session的信道形状;
public interface ISessionChannel<TSession> where TSession: ISession { TSession Session { get; } }
public interface IInputSession : ISession
public interface IInputSessionChannel : IInputChannel, IChannel, ICommunicationObject, ISessionChannel<IInputSession>
public interface IOutputSession : ISession
public interface IOutputSessionChannel : IOutputChannel, IChannel, ICommunicationObject, ISessionChannel<IOutputSession>
public interface IDuplexSession : IInputSession, IOutputSession, ISession
{ IAsyncResult BeginCloseOutputSession(AsyncCallback callback, object state); IAsyncResult BeginCloseOutputSession(TimeSpan timeout, AsyncCallback callback, object state); void CloseOutputSession(); void CloseOutputSession(TimeSpan timeout); void EndCloseOutputSession(IAsyncResult result); }
public interface IDuplexSessionChannel : IDuplexChannel, IInputChannel, IOutputChannel, IChannel, ICommunicationObject, ISessionChannel<IDuplexSession>
public interface IRequestSessionChannel : IRequestChannel, IChannel, ICommunicationObject, ISessionChannel<IOutputSession>
public interface IReplySessionChannel : IReplyChannel, IChannel, ICommunicationObject, ISessionChannel<IInputSession>
在以上支持会话的信道接口中,都实现了获取ISession接口的属性,其实就是获取唯一标识Id;