实例演示:自定义信道 WCF是一个极具扩展性的通信框架,不论是在服务模型层还是信道层都具有很多扩展点。信道层的可扩展性主要体现在可以通过自定义信道的方式实现针对消息的某种处理功能,比如可以创建压缩信道对发送的消息进行压缩以降低网络流量。自定义的信道并不实现针对消息的具体处理,而是在控制台中将当前调用的方法名称打印出来。当把信道应用于真正的WCF应用时,可以根据打印出来的类型知道具体执行的方法和执行的先后顺序。 创建自定义信道基类 现在我们为接下来需要创建的请求信道、回复信道和双工会话信道创建一个基类,并起名为SimpleChannelBase。如下面的代码片段所示,SimpleChannelBase继承自ChannelBase,其中定义了一个Print方法用于打印出指定的方法名称。 public abstract class SimpleChannelBase: ChannelBase { //其他成员 protected void Print(string methodName) { Console.WriteLine("{0}.{1}", this.GetType().Name, methodName); } } 信道存在于一个由多个信道连接而成的信道栈中。对于一个不处于栈尾的信道来说,在处理完消息后一般会把处理后的消息传递给后一个信道。反映在方法实现上就需要在执行本信道的某个方法之后,获得下一个信道对象并调用同名的方法。 如下面的代码所示,SimpleChannelBase定义了一个只读属性InnerChannel,表示在信道栈中与本信道相连的下一个信道。该属性在构造函数中初始化,在构造函数中还需要指定一个ChannelManagerBase对象表示创建该信道的信道监听器和信道工厂。 public abstract class SimpleChannelBase: ChannelBase { //其他成员 public ChannelBase InnerChannel { get; private set; } public SimpleChannelBase(ChannelManagerBase channelManager, ChannelBase innerChannel) :base(channelManager) { this.InnerChannel = innerChannel; } } 接下来需要做的工作就是实现抽象类ChannelBase的所有抽象方法了。所有抽象方法的实现方式都是一样的:先调用Print方法将当前的方法名称打印出来,再调用InnerChannel的同名方法。对于名称为OnXxx的方法(比如OnAbort、OnClose方法等),则直接调用InnerChannel对应的Xxx方法(比如Abort和Close方法等)。 public abstract class SimpleChannelBase: ChannelBase { //其他成员 protected override void OnAbort() { this.Print("OnAbort()"); this.InnerChannel.Abort(); } protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state) { this.Print("OnBeginClose()"); return this.InnerChannel.BeginClose(timeout, callback, state); } protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state) { this.Print("OnBeginOpen()"); return this.InnerChannel.BeginOpen(timeout, callback, state); } protected override void OnClose(TimeSpan timeout) { this.Print("OnClose()"); this.InnerChannel.Close(timeout); } protected override void OnEndClose(IAsyncResult result) { this.Print("OnEndClose()"); this.InnerChannel.EndClose(result); } protected override void OnEndOpen(IAsyncResult result) { this.Print("OnEndOpen()"); this.InnerChannel.EndOpen(result); } protected override void OnOpen(TimeSpan timeout) { this.Print("OnOpen()"); this.InnerChannel.Open(timeout); } } 除了实现定义在ChannelBase中的抽象方法之外,我们需要通过如下的方式重写虚方法GetProperty<T>。 public abstract class SimpleChannelBase: ChannelBase { //其他成员 public override T GetProperty<T>() { return this.InnerChannel.GetProperty<T>(); } } 自定义RequestChannel 现在我们通过继承SimpleChannelBase创建在客户端用于发送请求/接收回复的请求信道SimpleRequestChannel。如下面的代码所示,SimpleRequestChannel除了继承上面定义的SimpleChannelBase外,还实现了IRequestChannel接口。 public class SimpleRequestChannel : SimpleChannelBase, IRequestChannel { //其他成员 public IRequestChannel InnerRequestChannel { get { return (IRequestChannel)this.InnerChannel; } } public SimpleRequestChannel(ChannelManagerBase channelManager, IRequestChannel innerChannel) : base(channelManager, (ChannelBase)innerChannel) { } public IAsyncResult BeginRequest(Message message, TimeSpan timeout, AsyncCallback callback, object state) { this.Print("BeginRequest()"); return this.InnerRequestChannel.BeginRequest(message, timeout, callback, state); } } 我们采用与实现ChannelBase抽象方法一样的方式来实现定义在IRequestChannel接口中的方法。我们定义了类型为IRequestChannel 的InnerRequestChannel表示“下一个请求信道”,不过该属性和从SimpleChannelBase继承的属性InnerChannel返回的是同一个对象。 自定义ReplyChannel 在服务端接收请求/发送回复的回复信道SimpleReplyChannel也是SimpleChannelBase的子类,并且实现了IReplyChannel接口。SimpleReplyChannel采用与SimpleRequestChannel实现 IRequestChannel接口一样的方式实现了定义在IReplyChannel接口中的所有方法和属性。 public class SimpleReplyChannel: SimpleChannelBase, IReplyChannel { //其他成员 public IReplyChannel InnerReplyChannel { get { return (IReplyChannel)this.InnerChannel; } } public SimpleReplyChannel(ChannelManagerBase channelManager, IReplyChannel innerChannel) : base(channelManager, (ChannelBase)innerChannel) { this.Print("SimpleReplyChannel()"); } public IAsyncResult BeginReceiveRequest(TimeSpan timeout, AsyncCallback callback, object state) { this.Print("BeginReceiveRequest()"); return this.InnerReplyChannel.BeginReceiveRequest(timeout, callback, state); } } 自定义DuplexSessionChannel 我们接下来创建在会话模式下用于双工通信的SimpleDuplexSessionChannel。如下面的代码所示,继承自SimpleChannelBase的SimpleDuplexSessionChannel实现了接口IDuplexSessionChannel。SimpleDuplexSessionChannel对定义在IDuplexSessionChannel接口中所有方法的实现方式与SimpleRequestChannel和SimpleReplyChannel完全一致。 public class SimpleDuplexSessionChannel: SimpleChannelBase, IDuplexSessionChannel { //其他成员 public IDuplexSessionChannel InnerDuplexSessionChannel { get { return (IDuplexSessionChannel)this.InnerChannel; } } public SimpleDuplexSessionChannel(ChannelManagerBase channelManager, IDuplexSessionChannel innerChannel) : base(channelManager, (ChannelBase)innerChannel) { this.Print("SimpleDuplexSessionChannel()"); } public IAsyncResult BeginReceive(TimeSpan timeout, AsyncCallback callback, object state) { this.Print("BeginReceive()"); return this.InnerDuplexSessionChannel.BeginReceive(timeout, callback, state); } }