《WCF技术内幕》翻译36:第2部分_第6章_通道:创建自定义通道和本章小结

文章目录:
创建自定义通道
上一节已经看过了通道层里的基本类型,现在我们就来创建一个自定义通道。这个通道的目的就是要在控制台窗口里打印一个文本。因此,我们构建的通道对于演示通道的生命周期和程序调用不同的通道成员的时候都会非常有用。因为我们的自定义通道会在控制台窗口打印文本,所以有必要传递通道方法的委托调用给堆栈里的下一个通道。我们会把这个通道成为委托通道( DelegatorChannel)。在开始之前,有必要指出的是,这里还看不到一个通道运行必须的全部代码,直到第8章“绑定”会全部给出。没办法,创建通道还需要额外的工作。
创建自定义通道首要考虑的问题就是形状或者是通道要支持的形状。DelegatorChannel必须支持所有的通道形状( IInputChannel 、 IOutputChannel、IDuplexChannel、IReplyChannel、IRequestChannel以及所有的会话变量)。因此,我们必须构建多个通道,而且这些通道有固定的层次关系。

创建基类型

因为所有的通道都要使用通道状态机,并且每个通道必须保留堆栈里下一个通道实例的引用,因此把这些属性的声明放在一个基类里比较合理。所有的通道类型都会继承自这个基类型,所以把基类型定义为泛型更加合适。考虑到这些需求,我把基类型命名为 DelegatorChannelBase<TShape>,TShape必须是一个引用类型,而且继承自IChannel。(记住所有的通道类型都继承自IChannel。)DelegatorChannelBase<TShape>的是ChannelBase的子类型,因为这样它就会使用公共的状态机,并且可以实现Binding 的超时属性。DelegatorChannelBase<TShape>的初始定义如下:
InBlock.gif internal  class DelegatorChannelBase<TShape> : ChannelBase 
InBlock.gif 
InBlock.gif where TShape :  class, IChannel { 
InBlock.gif  // implementation not shown yet 
InBlock.gif}
添加构造函数
DelegatorChannelBase<TShape>对象不能放在堆栈的底部。换句话说,DelegatorChannelBase<TShape>对象必须拥有一个通道对象的引用,而且泛型类型表示的是通道形状,我们会把泛型类型作为构造函数的参数。当然构造函数还需要一个通道工厂的引用。当然,一个原因就是为了便于实现绑定的( time-out)超时属性。另外一个原因就是为了在创建通道完毕的时候可以通知一下通道工厂。你会在第7章里看到更多内容。基类的构造函数定义如下:
InBlock.gif internal  class DelegatorChannelBase<TShape> : ChannelBase 
InBlock.gif        where TShape :  class, IChannel { 
InBlock.gif  private TShape _innerChannel;  // reference the next channel in the stack 
InBlock.gif  private String _source;  // part of the String to print to the console 
InBlock.gif 
InBlock.gif  protected DelegatorChannelBase(ChannelManagerBase channelManagerBase, 
InBlock.gif                                                                 TShape innerChannel, 
InBlock.gif                                                                 String source) :  base(channelManagerBase){ 
InBlock.gif         if(innerChannel ==  null) { 
InBlock.gif             throw  new ArgumentNullException( "DelegatorChannelBase requires a non-null channel."
"innerChannel"); 
InBlock.gif        } 
InBlock.gif         // set part of the String to print to console 
InBlock.gif        _source = String.Format( "{0} CHANNEL STATE CHANGE: DelegatorChannelBase", source); 
InBlock.gif         // set the reference to the next channel 
InBlock.gif        _innerChannel = innerChannel; 
InBlock.gif } 
InBlock.gif  // other implementation not shown yet 
InBlock.gif
InBlock.gif注意_innerChannel和_source成员变量。像注释说的,这些成员变量是为了存储下一个通道的引用和要打印的字符。构造函数的第一个参数是ChannelManagerBase类型。ChannelManagerBase的引用通过ChannelBase构造函数存储起来。 
InBlock.gif 
InBlock.gif添加状态机 
InBlock.gif因为DelegatorChannelBase<TShape>继承自抽象类型ChannelBase,并且ChannelBase继承自抽象类型CommunicationObject但没有实现CommunicationObject里定义的成员,因此DelegatorChannelBase<TShape>类型必须实现这些抽象成员。因此DelegatorChannelBase<TShape>里的所有状态转换必须传播到堆栈里的其它通道,我们的状态转换方法委托会调用innerChannel通道变量,如下所示: 
InBlock.gif 
InBlock.gif internal  class DelegatorChannelBase<TShape> : ChannelBase 
InBlock.gif where TShape :  class, IChannel { 
InBlock.gif  private TShape _innerChannel;  // reference to the next channel 
InBlock.gif  private String _source;  // part of the String to output 
InBlock.gif  // provide the _innerChannel to derived types 
InBlock.gif  protected TShape InnerChannel { 
InBlock.gif                get {  return _innerChannel; } 
InBlock.gif        } 
InBlock.gif protected DelegatorChannelBase(ChannelManagerBase channelManagerBase, 
InBlock.gif                                                                 TShape innerChannel, 
InBlock.gif                                                                 String source) :  base(channelManagerBase){ 
InBlock.gif         if(innerChannel ==  null) { 
InBlock.gif             throw  new ArgumentNullException( "DelegatorChannelBase requires a non-null channel."
"innerChannel"); 
InBlock.gif        } 
InBlock.gif         // set part of the String to print to console 
InBlock.gif        _source = String.Format( "{0} CHANNEL STATE CHANGE: DelegatorChannelBase", source); 
InBlock.gif         // set the reference to the next channel 
InBlock.gif        _innerChannel = innerChannel; 
InBlock.gif } 
InBlock.gif  // IChannel implementation 
InBlock.gif  public  override T GetProperty<T>() { 
InBlock.gif         return  this._innerChannel.GetProperty<T>(); 
InBlock.gif } 
InBlock.gifCommunicationObject members #region CommunicationObject members 
InBlock.gif  protected  override  void OnAbort() { 
InBlock.gif        PrintHelper.Print(_source,  "OnAbort"); 
InBlock.gif         this._innerChannel.Abort(); 
InBlock.gif } 
InBlock.gif  protected  override IAsyncResult OnBeginClose(TimeSpan timeout, 
InBlock.gif                                                                                             AsyncCallback callback, 
InBlock.gif                                                                                             Object state) { 
InBlock.gif                 // output that the method was called 
InBlock.gif                PrintHelper.Print( _source,  "OnBeginClose"); 
InBlock.gif                 // delegate the call to the next channel 
InBlock.gif                 return  this._innerChannel.BeginClose(timeout, callback, state); 
InBlock.gif        } 
InBlock.gif  protected  override IAsyncResult OnBeginOpen(TimeSpan timeout, 
InBlock.gif                                                                                            AsyncCallback callback, 
InBlock.gif                                                                                            Object state) { 
InBlock.gif                 // output that the method was called 
InBlock.gif                PrintHelper.Print(_source,  "OnBeginOpen"); 
InBlock.gif                 // delegate the call to the next channel 
InBlock.gif                 return  this._innerChannel.BeginOpen(timeout, callback, state); 
InBlock.gif } 
InBlock.gif  protected  override  void OnClose(TimeSpan timeout) { 
InBlock.gif         // output that the method was called 
InBlock.gif        PrintHelper.Print(_source,  "OnClose"); 
InBlock.gif         // delegate the call to the next channel 
InBlock.gif         this._innerChannel.Close(timeout); 
InBlock.gif } 
InBlock.gif  protected  override  void OnEndClose(IAsyncResult result) { 
InBlock.gif         // output that the method was called 
InBlock.gif        PrintHelper.Print(_source,  "OnEndClose"); 
InBlock.gif         // delegate the call to the next channel 
InBlock.gif         this._innerChannel.EndClose(result); 
InBlock.gif } 
InBlock.gif  protected  override  void OnEndOpen(IAsyncResult result) { 
InBlock.gif         // output that the method was called 
InBlock.gif        PrintHelper.Print(_source,  "OnEndOpen"); 
InBlock.gif         // delegate the call to the next channel 
InBlock.gif         this._innerChannel.EndOpen(result); 
InBlock.gif } 
InBlock.gif  protected  override  void OnOpen(TimeSpan timeout) { 
InBlock.gif         // output that the method was called 
InBlock.gif        PrintHelper.Print(_source,  "OnOpen"); 
InBlock.gif         // delegate the call to the next channel 
InBlock.gif         this._innerChannel.Open(timeout); 
InBlock.gif } 
InBlock.gif #endregion 
InBlock.gif}
每个状态转换方法( OnAbort、OnBeginClose、OnBeginOpen、OnClose、OnEndClose、OnEndOpen和OnOpen )都会调用通道上对应的状态转换方法。每个状态转换方法也可以调用PrintHelper类型上的静态方法Print。PrintHelper类型只做在控制台窗口上打印字符的工作。

创建数据报通道

既然我们已经定义了通道的基类型,现在就定义数据报消息交换模式的通道吧。因为数据报发送通道必须继承 IInputChannel接口,接收通道必须继承IOutputChannel接口,所以我们需要DelegatorChannelBase<TShape>来继承这2个接口并实现他们。因为数据报接口被用作双工通信的接口,同时也会做会双工会话通道接口,所以我们把数据报通道定义为泛型。
注释:我们会从接收者开始,然后定义发送者。为了简明扼要,我就不把所有的代码都贴出来,而是着重展示代码里的实现模式。

数据报接收通道

数据报接收通道继承自 DelegatorChannelBase<TShape>类型并且实现了IInputChannel接口。和DelegatorChannelBase<TShape>一样,我们的数据报接收通道也会被定义为泛型类型,因此允许被双工通道复用,同样也可以被数据报和双工变量成员使用。因为这些需求,数据报接收通道命名为DelegatorInputChannel<TShape>,如下所示:
InBlock.gif internal  class DelegatorInputChannel<TShape> : 
InBlock.gif DelegatorChannelBase<TShape>, IInputChannel 
InBlock.gif where TShape: class, IInputChannel { 
InBlock.gif  // implementation not shown 
InBlock.gif}
DelegatorInputChannel<TShape>构造函数必须调用基类的构造函数,设置输出 String的值,并且调用PrintHelper.Print方法,如下所示:
InBlock.gif internal  class DelegatorInputChannel<TShape> : 
InBlock.gif DelegatorChannelBase<TShape>, IInputChannel 
InBlock.gif where TShape: class, IInputChannel { 
InBlock.gif          private String _source;  // store the String to output 
InBlock.gif  internal DelegatorInputChannel(ChannelManagerBase channelManagerBase, 
InBlock.gif                                                                 TShape innerChannel, 
InBlock.gif                                                                 String source) :  base(channelManagerBase, 
InBlock.gif                                                                                                             innerChannel, 
InBlock.gif                                                                                                             source) { 
InBlock.gif          // assign the name and generic parameter to the String 
InBlock.gif         _source = String.Format( "{0} CHANNEL: DelegatorInputChannel<{1}>"
InBlock.gif                                                            source, 
InBlock.gif                                                             typeof(TShape).Name); 
InBlock.gif          // output that the method was called 
InBlock.gif         PrintHelper.Print(_source,  "ctor"); 
InBlock.gif        } 
InBlock.gif  // other implementation not shown 
InBlock.gif}
下面我们需要实现 IInputChannel接口,为了简略起见,我只列举三个成员:

InBlock.gif public IAsyncResult BeginReceive(TimeSpan timeout, 
InBlock.gif                                                                 AsyncCallback callback, 
InBlock.gif                                                                Object state) { 
InBlock.gif  // output that the method was called 
InBlock.gif PrintHelper.Print(_source,  "BeginReceive"); 
InBlock.gif  // delegate the call to the next channel 
InBlock.gif  return  this.InnerChannel.BeginReceive(timeout, callback, state); 
InBlock.gif
InBlock.gif public IAsyncResult BeginReceive(AsyncCallback callback, Object state) { 
InBlock.gif  // output that the method was called 
InBlock.gif PrintHelper.Print(_source,  "BeginReceive"); 
InBlock.gif  // delegate the call to the next channel 
InBlock.gif  return  this.InnerChannel.BeginReceive(callback, state); 
InBlock.gif
InBlock.gif public IAsyncResult BeginTryReceive(TimeSpan timeout, 
InBlock.gif                                                                        AsyncCallback callback, 
InBlock.gif                                                                        Object state) { 
InBlock.gif  // output that the method was called 
InBlock.gif PrintHelper.Print(_source,  "BeginTryReceive"); 
InBlock.gif  // delegate the call to the next channel 
InBlock.gif  return  this.InnerChannel.BeginTryReceive(timeout, callback, state); 
InBlock.gif
InBlock.gifDelegatorInputChannel<TShape>类型只有在其它成员定义结束以后才会完整(EndReceive、EndTryReceive、EndWaitForMessage、 LocalAddress、Receive、TryReceive和WaitForMessage)。 
InBlock.gif 
InBlock.gif数据报发送通道 
InBlock.gif数据报发送通道与接收通道很相似,区别仅仅在于它实现了IOutputChannel接口。为了避免重复,我们会给出这个类型定义,而DelegatorInputChannel<TShape>实现则交给读者来做: 
InBlock.gif 
InBlock.gif internal  class DelegatorOutputChannel<TShape> : 
InBlock.gif DelegatorChannelBase<TShape>, IOutputChannel where 
InBlock.gif TShape:  class, IOutputChannel { 
InBlock.gif  private String _source;  // store the String to output 
InBlock.gif  internal DelegatorOutputChannel(ChannelManagerBase channelManagerBase, 
InBlock.gif                                                                    TShape innerChannel, 
InBlock.gif                                                                    String source) :  base(channelManagerBase, 
InBlock.gif                                                                                                                innerChannel, 
InBlock.gif                                                                                                                source) { 
InBlock.gif        _source = String.Format( "{0} CHANNEL: DelegatorOutputChannel<{1}>", source, 
InBlock.gif typeof(TShape).Name); 
InBlock.gif         // output that the method was called 
InBlock.gif        PrintHelper.Print(_source,  "ctor"); 
InBlock.gif } 
InBlock.gifIOutputChannel Members #region IOutputChannel Members 
InBlock.gif  public IAsyncResult BeginSend(Message message, 
InBlock.gif                                                                TimeSpan timeout, 
InBlock.gif                                                                AsyncCallback callback, 
InBlock.gif                                                                Object state) { 
InBlock.gif         // output that the method was called 
InBlock.gif        PrintHelper.Print(_source,  "BeginSend"); 
InBlock.gif         // delegate the call to the next channel 
InBlock.gif         return  this.InnerChannel.BeginSend(message, timeout, callback, state); 
InBlock.gif } 
InBlock.gif  public IAsyncResult BeginSend(Message message, AsyncCallback callback,  object state) { 
InBlock.gif         // output that the method was called 
InBlock.gif        PrintHelper.Print(_source,  "BeginSend"); 
InBlock.gif         // delegate the call to the next channel 
InBlock.gif         return  this.InnerChannel.BeginSend(message, callback, state); 
InBlock.gif } 
InBlock.gif  public  void EndSend(IAsyncResult result) { 
InBlock.gif         // output that the method was called 
InBlock.gif        PrintHelper.Print(_source,  "EndSend"); 
InBlock.gif         // delegate the call to the next channel 
InBlock.gif         this.InnerChannel.EndSend(result); 
InBlock.gif } 
InBlock.gif  public EndpointAddress RemoteAddress { 
InBlock.gif        get { 
InBlock.gif             // output that the method was called 
InBlock.gif            PrintHelper.Print(_source,  "RemoteAddress"); 
InBlock.gif          // delegate the call to the next channel 
InBlock.gif             return  this.InnerChannel.RemoteAddress; } 
InBlock.gif        } 
InBlock.gif  public  void Send(Message message, TimeSpan timeout) { 
InBlock.gif         // output that the method was called 
InBlock.gif        PrintHelper.Print(_source,  "Send"); 
InBlock.gif         // delegate the call to the next channel 
InBlock.gif         this.InnerChannel.Send(message, timeout); 
InBlock.gif        } 
InBlock.gif  public  void Send(Message message) { 
InBlock.gif         // output that the method was called 
InBlock.gif        PrintHelper.Print(_source,  "Send"); 
InBlock.gif         // delegate the call to the next channel 
InBlock.gif         this.InnerChannel.Send(message); 
InBlock.gif } 
InBlock.gif  public Uri Via { 
InBlock.gif        get { 
InBlock.gif             // output that the method was called 
InBlock.gif            PrintHelper.Print(_source,  "Via"); 
InBlock.gif             // delegate the call to the next channel 
InBlock.gif             return  this.InnerChannel.Via; 
InBlock.gif        } 
InBlock.gif } 
InBlock.gif #endregion 
InBlock.gif}
双工通道
想一下通道的形状,记得 IDuplexChannel接口是IInputChannel  和IOutputChannel的结合体。因为我们已经有了一个类型实现了IInputChannel  和IOutputChannel,所以我们可以服用这个类型作为我们的基类。与IOutputChannel 相比,IInputChannel接口包含更多的成员,所以(没有意外的话)DelegatorInputChannel<TShape>类型会作为我们的双工通信的基类型。
因为双工通道实现了 IDuplexChannel接口,我们来调用DelegatorDuplexChannel双工通道,并且在基类里使用IDuplexChannel作为泛型参数,如下所示:
 
 
InBlock.gif internal class DelegatorDuplexChannel :
InBlock.gif DelegatorInputChannel<IDuplexChannel>, IDuplexChannel {
InBlock.gif // implementation not shown yet
InBlock.gif}
Because the DelegatorDuplexChannel is very similar to the DelegatorInputChannel<TShape> type definition, I will show only part of the type definition here:
DelegatorDuplexChannel与DelegatorInputChannel<TShape>的定义很类似,我这里只展示类型定义部分:
InBlock.gif internal  class DelegatorDuplexChannel : 
InBlock.gif DelegatorInputChannel<IDuplexChannel>, IDuplexChannel { 
InBlock.gif  private String _source;  // store the String to output 
InBlock.gif  internal DelegatorDuplexChannel(ChannelManagerBase channelManagerBase, 
InBlock.gif                                                                     // use IDuplexSession as the 2nd parameter 
InBlock.gif                                                                    IDuplexChannel innerChannel, 
InBlock.gif                                                                    String source) :  base(channelManagerBase, 
InBlock.gif                                                                                                                innerChannel, 
InBlock.gif                                                                                                                source) { 
InBlock.gif         _source = String.Format( "{0} CHANNEL: DelegatorDuplexChannel", source); 
InBlock.gif         PrintHelper.Print(_source,  "ctor"); 
InBlock.gif        } 
InBlock.gifIOutputChannel Members #region IOutputChannel Members 
InBlock.gif  public IAsyncResult BeginSend(Message message, 
InBlock.gif                                                                TimeSpan timeout, 
InBlock.gif                                                                AsyncCallback callback, 
InBlock.gif                                                                Object state) { 
InBlock.gif        PrintHelper.Print(_source,  "BeginSend"); 
InBlock.gif         return  this.InnerChannel.BeginSend(message, timeout, callback, state); 
InBlock.gif } 
InBlock.gif  // other IOutputChannel Members omitted for brevity 
InBlock.gif #endregion 
InBlock.gif
InBlock.gif双工会话通道 
InBlock.gif从对象模型的角度来看,会话通道形状与非会话通道只有一些细微的差别。例如,IDuplexSessionChannel是IDuplexChannel和 ISessionChannel<IDuplexSession>的结合体。因为我们已有有了一个DelegatorDuplexChannel类型定义(它实现了IDuplexChannel接口),创建一个会话通道仅仅是一个继承DelegatorDuplexChannel并实现IDuplexSessionChannel接口的问题,如下所示: 
InBlock.gif 
InBlock.gif internal  sealed  class DelegatorDuplexSessionChannel : 
InBlock.gif DelegatorDuplexChannel, IDuplexSessionChannel { 
InBlock.gif  private IDuplexSessionChannel _innerSessionChannel;  // reference the next 
InBlock.gif                                                                                                             // sessionful channel 
InBlock.gif  private String _source;  // store the String to output 
InBlock.gif  internal DelegatorDuplexSessionChannel(ChannelManagerBase 
InBlock.gif        channelManagerBase, IDuplexSessionChannel innerChannel, String source) 
InBlock.gif        :  base(channelManagerBase, innerChannel, source) { 
InBlock.gif        _source = String.Format( "{0} CHANNEL: DelegatorDuplexSessionChannel"
InBlock.gif            source); 
InBlock.gif        PrintHelper.Print(_source,  "ctor"); 
InBlock.gif         // assign the reference to the next sessionful channel 
InBlock.gif         this._innerSessionChannel = innerChannel; 
InBlock.gif } 
InBlock.gif     // IDuplexSessionChannel member that is not defined in IDuplexChannel 
InBlock.gif  public IDuplexSession Session { 
InBlock.gif        get { 
InBlock.gif            PrintHelper.Print(_source,  "Session"); 
InBlock.gif             return  this._innerSessionChannel.Session; } 
InBlock.gif        } 
InBlock.gif}
DelegatorDuplexChannel包含一个 IDuplexChannel类型的成员变量,我们需要通过一个IDuplexSessionChannel类型的局部变量来存储同一个对象的引用。这样做可以使得我们容易地添加Session属性到我们的类型定义上。
注释:有了DelegatorChannelBase < TShape > ,DelegatorInputChannel < TShape > ,DelegatorOutputChannel < TShape > ,DelegatorDuplexChannel和 DelegatorDuplexSessionChannel里使用的模式,我们就可以很容易地添加IInputSessionChannel、IOutputSessionChannel、 IRequestChannel、IReplyChannel、IRequestSessionChannel和IReplySessionChannel的实现代码。因为有些类型是创建通道时必备的,所以下面两章,我们会构建一些WCF程序来使用这些类型。
本章小结
因为实际上,通道来执行消息相关的工作,所以尽管WCF开发人员不会看到这些,但是它们仍然是所有WCF程序必不可少的部分,。这一章里,我们学习了通道状态机,通道API里的关键类型,以及自定义通道。在第7章和第8章里,我们会继续学习如何在WCF程序里使用我们的自定义通道。




 本文转自 frankxulei 51CTO博客,原文链接: http://blog.51cto.com/frankxulei/318552 ,如需转载请自行联系原作者




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值