[WCF中的Binding模型]之二: 信道與信道棧(Channel and Channel Stack)
[2] [WCF中的Binding模型]之二: 信道與信道棧(Channel and Channel Stack)
[3] [WCF中的Binding模型]之二: 信道與信道棧(Channel and Channel Stack)
[4] [WCF中的Binding模型]之二: 信道與信道棧(Channel and Channel Stack)
WCF采用基于消息交換的通信方式,而綁定則實現了所有的通信細節。綁定通過創建信道棧實現了消息的編碼與傳輸,以及對WS-*協議的實現。在這一節中,我們就來著重介紹WCF中的信道和信道棧。在正式開始對信道和信息棧的介紹之前,我們先來介紹兩個重要的類型:CommunicationObject和DefaultCommunicationTimeouts。
CommunicationObject與DefaultCommunicationTimeouts
WCF綁定模型涉及多種類型的組件,比如信道、信道監聽器、信道工廠等等。從功能上講,這些對象都是為通信服務的,我們可以把它們稱為通信對象(Communication Object)。對于這些通信對象來說,在通信不同的階段,它們往往具有不同的狀態;從整個通信的生命周期來看,在不同階段過渡的過程中,它們具有一些相似的狀態轉換方式。
WCF定義了一個特殊的接口,System.ServiceModel.ICommunicationObject,來管理通信對象的狀態和狀態的轉換。下面是ICommunicationObject的定義:
public interface ICommunicationObject { // Events event EventHandler Closed; event EventHandler Closing; event EventHandler Faulted; event EventHandler Opened; event EventHandler Opening; // Methods void Open(); void Open(TimeSpan timeout); IAsyncResult BeginOpen(AsyncCallback callback, object state); IAsyncResult BeginOpen(TimeSpan timeout, AsyncCallback callback, object state); void EndOpen(IAsyncResult result); void Close(); void Close(TimeSpan timeout); IAsyncResult BeginClose(AsyncCallback callback, object state); IAsyncResult BeginClose(TimeSpan timeout, AsyncCallback callback, object state); void EndClose(IAsyncResult result); void Abort(); // Properties CommunicationState State { get; } }
ICommunicationObject的State屬性,表示通信對象當前所處的狀態。該屬性通過一個名為System.ServiceModel.CommunicationState的枚舉類型表示,通信對象典型的六種狀態都定義在CommunicationState中:被創建(Created)、正被開啟(Opening)、已經被開啟(Opened)、正被關閉(Closing)、已經被關閉(Closed)已經出錯(Faulted)。
public enum CommunicationState { Created, Opening, Opened, Closing, Closed, Faulted }
ICommunicationObject定義了以下三種類型的成員:
- 事件:當正在進行狀態轉化,或者是狀態轉換成功,會觸發相應的事件。通過注冊相應的事件,可以在某個狀態轉換環節中注入你需要的處理操作。
- 方法:定義了三種類型的操作:開啟(open)、關閉(close)、中止(abort)。關于“關閉”和“中止”在功能上具有相似之出,都是斷開連接、回收對象。不過它們具有不同之處,很多英文文章或書籍將“關閉(close)”成為“graceful shutdown(優雅地關閉)”,而將“中止(abort)”描述為“immediate shutdown(立即關閉)”。那我們關閉電腦來說,前面一種是通過操作系統進行關閉,后一種則是直接切斷電源。對于前一種方式,在關閉過程中,會進行一些IO操作。
- 屬性:在上面已經提到,屬性State代表通信對象當前所處的狀態。
由于WCF處理的是跨應用程序域(Application Domain)、跨機器甚至是跨網絡的通信。所以WCF服務調用的大部分時間都在進行象網絡傳輸這樣的IO操作,對于這種IO綁定(IO bound)的操作,對于多線程、異步的考慮肯定是可以不免的,所以ICommunicationObject中的開啟和關閉操作,既定義了一個的同步方法,也按照異步編程模型(APM:Asynchronous Programming Mode)定義了異步方法。
除了簡單定義ICommunicationObject接口之外,WCF還定義了一個實現了該接口的基類:System.ServiceModel.Channels.CommunicationObject。
public abstract class CommunicationObject : ICommunicationObject { ... }
在WCF體系中,很多的基于通信的基類都繼承自CommunicationObject,比如信道的基類System.ServiceModel.Channels.ChannelBase;信道工廠和信道監聽器的基類System.ServiceModel.Channels.ChannelManagerBase;ServiceHost的基類System.ServiceModel.ServiceHostBase;信道分發器的基類System.ServiceModel.Dispatcher.ChannelDispatcherBase;等等。大體的繼承結構如圖3-8所示 的類圖所示。
圖3-8 CommunicationObject繼承關系
由于WCF往往需要跨域網絡進行服務的訪問,較之一般的方法調用,服務訪問的所花的時間往往較長,所以對超時的處理顯得異常重要。比如對于消息的發送,可能由于網絡的故障,該消息在一端時間內根本無法成功發送,客戶端程序不可能無限制地等待下去。一般的情況下,我們會設定一個操作執行的所允許的最大時限,一旦超時則取消操作,并進行相應的超時處理。
我們回顧一下ICommunicationObject的Open和BeginOpen方法,我們會發現它們各有兩個重載,其中一個具有的TimeSpan類型的timeout參數,另一個則沒有。在這里的timeout參數實際上代表Open方法執行的超時時間,如果Open操作執行的時間過長,一旦超過了該事件,操作將被立即中止。
public interface ICommunicationObject { void Open(); void Open(TimeSpan timeout); IAsyncResult BeginOpen(AsyncCallback callback, object state); IAsyncResult BeginOpen(TimeSpan timeout, AsyncCallback callback, object state); ... ... }
可能讀者會問,對于沒有timeout參數的操作,比如無參的Open方法,是否意味著沒有這樣的超時限制,操作將會一直執行下去直到操作正常結束呢?答案是否定的,實際上,對于沒有顯式指定超時時限的操作,采用的是默認的超時時限。WCF為所有需要默認超時時限的通信對象定義了一個接口:System.ServiceModel.IDefaultCommunicationTimeouts。在IDefaultCommunicationTimeouts中定一個了四個Timeout屬性,分別定義了開啟、關閉、發送、接收四大操作的超時時限。
public interface IDefaultCommunicationTimeouts { // Properties TimeSpan CloseTimeout { get; } TimeSpan OpenTimeout { get; } TimeSpan ReceiveTimeout { get; } TimeSpan SendTimeout { get; } }
很多的基于通信的基類都實現了IDefaultCommunicationTimeouts接口,比如信道的基類System.ServiceModel.Channels.ChannelBase信道工廠和信道監聽器的基類System.ServiceModel.Channels.ChannelManagerBase;以及所有綁定對象的基類System.ServiceModel.Channels.Binding等等。