程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> 《WCF技術內幕》38:第2部分_第7章_通道管理器:通道偵聽器

《WCF技術內幕》38:第2部分_第7章_通道管理器:通道偵聽器

編輯:關於.NET

接收者:通道偵聽器

和它們的名字暗示的一樣,通道偵聽器就是為了創建通道並偵聽傳入的消息 。這個模型借鑒了伯克利Socket編程API。在WCF裡,這個模型可以在 Windows Socket(Winsock) API裡看到。在.NET Framework編程裡,這個模型存在於 System.Net.Sockets命名空間裡。在這個模型裡,TcpListener或Socket會綁定 一個地址,然後被動偵聽連接傳入的消息。當連接建立以後(例如,客戶端鏈接 到偵聽器),會有一個以Accept開頭的方法返回一個TcpListener或Socket的實 例,程序可以使用這個對象來接受數據。

在WCF裡,通道偵聽器做著相同的工作。它們會綁定一個URI,然後等待傳入 的消息,當連接建立以後一個以Accept開頭的方法會返回一個通道的實例。然後 程序可以使用這個通道對象來接收消息。盡管所有的通道都定義了以Accept 開 頭的方法,但是只有偵聽器類型的偵聽器才會偵聽消息。舉例說明一下,考慮一 下通道偵聽器的堆棧。通道偵聽器處於堆棧的最底層。傳輸通道偵聽器是唯一的 一個綁定地址並且開始偵聽連接消息的通道。堆棧處於上面通道偵聽器會依次調 用下一個通道偵聽器的Accept方法,直到調用最底層的傳輸通道偵聽器。

圖7-1:傳輸通道堆棧

但是也不是所有的傳輸通道偵聽器都是這樣工作的。因為各自傳輸層固有的 差別,導致了他們之間存在很大的不同。例如,面向連接的傳輸通道偵聽器(例 如 TCP/IP和named pipe)在接收了一個消息以後會返回一個通道。面向非連接 的傳輸通道偵聽器(例如MSMQ)會立即返回一個通道,因為不需要等待請求消息 。

The IChannelListener Interface

IChannelListener接口

所有的通道都實現了System.ServiceModel.Channels.IChannelListener接口 。這個接口會強制所有的通道實現通道狀態機,而且包含一些基本的通道偵聽器 成員。IChannelListener的定義如下:

public interface IChannelListener : ICommunicationObject  {
     IAsyncResult BeginWaitForChannel(TimeSpan  timeout,AsyncCallback callback,Object state);
     Boolean EndWaitForChannel(IAsyncResult result);
     Boolean WaitForChannel(TimeSpan timeout);

     T GetProperty<T>() where T: class;
     // the listening address
     Uri Uri { get; }
}

WaitForChannel方法(包含異步方法)可以返回一個Boolean值,來表示一個 通道是否可用。Uri可以訪問偵聽地址。GetProperty<T>可以被實現的 IChannel的類使用。IChannelListener接口沒有實現IChannel,因為IChannel是 區別API裡通道的標識。例如,對於類型和IChannel接口,許多泛型參數是受約 束的。目的就是為了約束擁有特定形狀通道的參數。如果IChannelListener實現 了 Channel,通道偵聽器就可以在很多地方使用,而不是只能被通道調用,並且 堆棧和堆棧裡的通道偵聽器都必須支持查詢功能。

IChannelListener<TChannel>接口

所有的通道同樣也實現IChannelListener<TChannel>接口。這裡我們 會第一次看到伯克利Socket API的Accept范式,如下所示:

public interface IChannelListener<TChannel> :  IChannelListener,
                                                where TChannel: class,
                                                                IChannel  {
  TChannel AcceptChannel();
  TChannel AcceptChannel(TimeSpan timeout);
  IAsyncResult BeginAcceptChannel(AsyncCallback callback, Object  state);
  IAsyncResult BeginAcceptChannel(TimeSpan timeout,
                                   AsyncCallback callback,
                                   Object state);
  TChannel EndAcceptChannel(IAsyncResult result);
}

注意,接口定義把泛型類型指定為一個具體的IChannel。在WCF API裡,實現 特定形狀的通道必須遵守這個規則。整體來看,這意味著通道偵聽器必須引用一 個通道形狀。這與通道使用通道形狀的方式不同。通道是實現通道形狀,而通道 偵聽器引用一個通道形狀並且使用這個引用來創建特定的通道。

實現IChannelListener<TChannel>接口的類型必須通過AcceptChannel 方法(包含異步實現)返回一個通道的實例。與通道層的其它成員一樣, AcceptChannel也包含一個重載的方法,它可以接受一個TimeSpan參數。因為消 息接收程序可以長時間等待接受消息,所以,參數經常是TimeSpan.MaxValue。

ChannelListenerBase類型

所有的通道偵聽器都繼承自抽象類型 System.ServiceModel.Channels.ChannelListenerBase。它的定義如下:

public abstract class ChannelListenerBase :  ChannelManagerBase,
                                              IChannelListener,
                                              ICommunicationObject {
  protected ChannelListenerBase();
  protected ChannelListenerBase(IDefaultCommunicationTimeouts  timeouts);

  // IChannelListener implementation
  public IAsyncResult BeginWaitForChannel(TimeSpan timeout,
                                            AsyncCallback callback,
                                            Object state);
  public bool EndWaitForChannel(IAsyncResult result);
  public bool WaitForChannel(TimeSpan timeout);

  // Extensibility points for IChannelListener members
  protected abstract IAsyncResult OnBeginWaitForChannel(TimeSpan  timeout,
     AsyncCallback callback, Object state);
  protected abstract bool OnEndWaitForChannel(IAsyncResult  result);
  protected abstract bool OnWaitForChannel(TimeSpan  timeout);
      public abstract Uri Uri { get; }

  // Query mechanism
  public virtual T GetProperty<T>() where T:  class;

  // CommunicationObject timeouts
  protected override TimeSpan DefaultCloseTimeout { get; }
  protected override TimeSpan DefaultOpenTimeout { get; }

  // ChannelManagerBase timeouts
  protected override TimeSpan DefaultReceiveTimeout { get; }
  protected override TimeSpan DefaultSendTimeout { get; }
}

這裡非常有趣的一點就是,有一個構造函數接受一個TimeSpan參數。由於 ChannelListenerBase的類型層次的原因,它定義了4個protected的TimeSpan屬 性。WCF 類型系統對每個超時屬性默認設置的值都是1分鐘。如果這個值不能滿 足通道(包括子通道)的需求,你可以通過ChannelListenerBase構造函數傳遞 一個IDefaultCommunicationTimeouts參數。在這個構造函數裡,超時的值會設 置到每個相關的屬性上。你會在第8章“綁定”裡看到Binding實現了 IDefaultCommunicationTimeouts接口,而且這個也是用戶控制通道超時屬性的 一種方式。

ChannelListenerBase<TChannel>類型

通道偵聽器也繼承自抽象類型 System.ServiceModel.Channels.ChannelListenerBase<TChannel>。這個 類型是ChannelListenerBase的子類型,而且實現了 IChannelListener<TChannel>接口,如下所示:

public abstract class ChannelListenerBase<TChannel>  : ChannelListenerBase,
     IChannelListener<TChannel>, where TChannel:  class, IChannel {

  protected ChannelListenerBase();
  protected ChannelListenerBase(IDefaultCommunicationTimeouts  timeouts);

  // IChannelListener<TChannel> implementation
  public IAsyncResult BeginAcceptChannel(AsyncCallback  callback,
                                           Object state);
  public IAsyncResult BeginAcceptChannel(TimeSpan timeout,
     AsyncCallback callback, Object state);
  public TChannel EndAcceptChannel(IAsyncResult result);
  public TChannel AcceptChannel();
  public TChannel AcceptChannel(TimeSpan timeout);

  // extensibility points for  IChannelListener<TChannel>
  protected abstract TChannel OnAcceptChannel(TimeSpan  timeout);
  protected abstract IAsyncResult OnBeginAcceptChannel(TimeSpan  timeout,
     AsyncCallback callback, Object state);
  protected abstract TChannel OnEndAcceptChannel(IAsyncResult  result);
}

創建自定義通道偵聽器

既然已經學習完了通道偵聽器裡使用的類型,現在我們自己來創建一個通道 偵聽器。前面一章裡,我們學習了如何構建不同的DelegatorChannel通道。這一 節裡,我們會學習如何在消息接受程序端創建一個通道偵聽器,而且這些通道偵 聽器能夠創建DelegatorChannel通道。當然這些代碼直到第8章才能全部給出。

當創建一個通道偵聽器的時候,我們首先考慮的就是要支持的通道形狀。因 為我們的DelegatorChannel例子要支持任何一種通道形狀,所以我們的通道偵聽 器必須能夠創建所有已知的DelegatorChannel通道。在第6章裡,我們使用泛型 參數,這給我們的編碼帶來了很大的靈活性,這裡我們也會這麼做。

我們就從熟悉的地方開始。這裡最簡單的方法就是繼承 ChannelListenerBase<TChannel>類型。我們必須使得我們的通道偵聽器 類型支持泛型和任何可能的通道形狀。定義如下:

internal sealed class  DelegatorChannelListener<TShape> :
  ChannelListenerBase<TShape> where TShape : class,  IChannel {
  // implementation omitted for clarity
}

注意這裡修改了DelegatorChannelListener<TShape>類型的訪問控制 器。和第6章裡的通道定義一樣,這裡的通道偵聽器不需要外部調用者訪問。我 們會在第8章裡介紹通過Binding和BindingElement對象訪問此對象。現在我們已 經定義完了通道偵聽器的基類型,現在就來實現它。下面是 DelegatorChannelListener<TShape>的具體實現:

internal sealed class  DelegatorChannelListener<TShape> :
     ChannelListenerBase<TShape> where TShape :  class, IChannel {
  // field referencing the next channel listener
  IChannelListener<TShape> _innerListener;

  // String to output to console
  String _consolePrefix = "LISTENER:  DelegatorChannelListener";

  // builds the next channel listener, then assigns it  to
  // the _innerListener field
  public DelegatorChannelListener(BindingContext context) {
     PrintHelper.Print(_consolePrefix, "ctor");
     this._innerListener =  context.BuildInnerChannelListener<TShape>();
  }

  // Creates a DelegatorChannel of the correct shape and  returns it
  private TShape WrapChannel(TShape innerChannel) {

     if(innerChannel == null) {
       throw new ArgumentNullException("innerChannel cannot  be null", "innerChannel");
     }
     if(typeof(TShape) == typeof(IInputChannel)) {
       return (TShape)(Object)new  DelegatorInputChannel<IInputChannel>(this,
(IInputChannel)innerChannel, "RECEIVE");
     }
     if(typeof(TShape) == typeof(IReplyChannel)) {
       return (TShape)(object)new DelegatorReplyChannel (this, (IReplyChannel)innerChannel,
"RECEIVE");
     }
     if(typeof(TShape) == typeof(IDuplexChannel)) {
      return (TShape)(object)new DelegatorDuplexChannel(this,  (IDuplexChannel)innerChannel,
"RECEIVE");
     }
     if(typeof(TShape) == typeof(IInputSessionChannel)) {
       return (TShape)(object)new  DelegatorInputSessionChannel(this,
(IInputSessionChannel)innerChannel, "RECEIVE");
     }
     if(typeof(TShape) == typeof(IReplySessionChannel)) {
       return (TShape)(object)new  DelegatorReplySessionChannel(this,
(IReplySessionChannel)innerChannel, "RECEIVE");
     }
     if(typeof(TShape) == typeof(IDuplexSessionChannel))  {
       return (TShape)(object)new  DelegatorDuplexSessionChannel(this,
(IDuplexSessionChannel)innerChannel, "RECEIVE");
     }

     // cannot wrap this channel
     throw new ArgumentException(String.Format("invalid  channel shape passed:{0}",
innerChannel.GetType()));
  }

      // IChannelListener<TChannel> members
  protected override IAsyncResult OnBeginAcceptChannel(TimeSpan  timeout, AsyncCallback
callback, object state) {
     PrintHelper.Print(_consolePrefix,  "OnBeginAcceptChannel");
     return this._innerListener.BeginAcceptChannel(timeout,  callback, state);
  }

  protected override TShape OnEndAcceptChannel(IAsyncResult  result) {
     // create and return the channel
     PrintHelper.Print(_consolePrefix,  "OnEndAcceptChannel");
     TShape innerChannel = _innerListener.EndAcceptChannel (result);
     // when closing, _inner.EndAcceptChannel returns null,  nothing to wrap
     if (innerChannel != null) {
       return WrapChannel(innerChannel);
     }
     return null;
  }

      protected override TShape OnAcceptChannel(TimeSpan  timeout){
     // delegate to next channel, wrap it, and return  it
     PrintHelper.Print(_consolePrefix, "OnAcceptChannel");
     TShape innerChannel = _innerListener.AcceptChannel (timeout);
     // when closing, _inner.AcceptChannel returns null,  nothing to wrap
     if (innerChannel != null) {
       return WrapChannel(innerChannel);
     }
     return null;
  }

  // IChannelListener members
  protected override IAsyncResult OnBeginWaitForChannel(TimeSpan  timeout, AsyncCallback
callback, object state) {
     PrintHelper.Print(_consolePrefix,  "OnBeginWaitForChannel");
     return this._innerListener.BeginWaitForChannel(timeout,  callback, state);
  }

  protected override bool OnEndWaitForChannel(IAsyncResult  result) {
     PrintHelper.Print(_consolePrefix,  "OnEndWaitForChannel");
     return this._innerListener.EndWaitForChannel(result);
  }

  protected override bool OnWaitForChannel(TimeSpan timeout)  {
     PrintHelper.Print(_consolePrefix, "OnWaitForChannel");
     return this._innerListener.WaitForChannel(timeout);
  }

  public override Uri Uri {
     get {
       PrintHelper.Print(_consolePrefix, "Uri");
       return this._innerListener.Uri;
     }
  }
  public override T GetProperty<T>() {
     PrintHelper.Print(_consolePrefix, "GetProperty<" +  typeof(T) + ">");
     return this._innerListener.GetProperty<T>();
  }

  // CommunicationObject members
  protected override void OnAbort() {
     PrintHelper.Print(_consolePrefix, "OnAbort");
     this._innerListener.Abort();
  }

  protected override IAsyncResult OnBeginClose(TimeSpan  timeout, AsyncCallback callback,
object state) {
     PrintHelper.Print(_consolePrefix, "OnBeginClose");
     return this._innerListener.BeginClose(timeout, callback,  state);
  }

  protected override IAsyncResult OnBeginOpen(TimeSpan timeout,  AsyncCallback callback,
object state) {
     PrintHelper.Print(_consolePrefix, "OnBeginOpen");
     return this._innerListener.BeginOpen(timeout, callback,  state);
  }

  protected override void OnClose(TimeSpan timeout) {
     PrintHelper.Print(_consolePrefix, "OnClose");
     this._innerListener.Close(timeout);
  }

  protected override void OnEndClose(IAsyncResult result)  {
     PrintHelper.Print(_consolePrefix, "OnEndClose");
     this._innerListener.EndClose(result);
  }

  protected override void OnEndOpen(IAsyncResult result) {
     PrintHelper.Print(_consolePrefix, "OnEndOpen");
     this._innerListener.EndOpen(result);
  }

  protected override void OnOpen(TimeSpan timeout) {
     PrintHelper.Print(_consolePrefix, "OnOpen");
     this._innerListener.Open(timeout);
  }
}

這裡要補充一下。從構造函數開始。和前面幾章裡DelegatorChannel的定義 一樣,DelegatorChannelListener<TShape>對象可以與其它通道偵聽器在 堆棧裡共存。雖然有好幾種建立通道偵聽器堆棧的方法,但是最終都是傳輸通道 偵聽器位於堆棧的底部。DelegatorChannelListener<TShape> 類型定義 了幾個IChannelListener<TShape>類型的成員,而且可以通過構造函數賦 值。在第8章裡會介紹,Binding 創建通道偵聽器堆棧的主要方式就是使用 BindingContext對象。另外一個方法就是改變構造函數的參數類型為 IChannelListener<TShape>。這時調用者負責使用BindingContext對象。 我個人認為,這個差別問題不大。

DelegatorChannelListener<TShape>裡的大部分方法都和 DelegatorChannel裡的方法很相似,它們都是簡單地調用堆棧裡的下一個方法。 有趣的是,DelegatorChannelListener<TShape>的私有方法WrapChannel 。這個方法的作用就是返回擁有 TShape 泛型參數的DelegatorChannel的實例。 innerChannel參數傳遞給DelegatorChannel的構造函數,這樣就可以正常地創建 通道堆棧。OnAcceptChannel 和OnEndAcceptChannel是僅有的調用WrapChannel 的方法。在調用之前,它們必須調用成員變量innerListener的方法(分別調用 AcceptChannel 和EndAcceptChannel)並且把通道偵聽器傳遞給WrapChannel方 法。

當通道偵聽器堆棧關閉的時候,DelegatorChannelListener<TShape> 類型會循環調用下一個通道偵聽器的關閉方法(比如,Close、OnClose、Abort 和OnAbort)。如果在關閉方法以前調用了BeginAcceptChannel或AcceptChannel ,委托調用就會返回null。這種情況下,OnEndAcceptChannel或AcceptChannel 方法也會返回null。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved