發送者:通道工廠
發送者使用通道工廠來創建通道。它們和通道偵聽器的許多特性相似,但是 不同的是它們駐留在發送者內部,而且不需要從連接上偵聽消息。它們會通過 CreateChannel方法創建符合要求的連接通道而不是消極等待消息到來。和通道 偵聽器一樣,通道工廠也是根據它們創建的通道功能來分類的。
實際上,這意味著每個傳輸通道都會有一個與之關聯的通道工廠,比如支持 WS-*協議的通道。和通道偵聽器一樣,用戶代碼無法直接實例化通道工廠,需要 借助於Binding(你會在第8章裡看到詳細的介紹)。通道工廠類型都繼承自 ChannelManagerBase。而類型層次的其它部分則不相同。本節裡,我們會先研究 一下通道工廠裡不同的類型,然後會創建一個自定義通道工廠來繼續學習我們的 DelegatorChannel例子。
IChannelFactory接口
所有的通道工廠都繼承了IChannelFactory接口。這個接口實現了 ICommunicationObject接口,因此可以強制它的繼承者實現通道狀態機。當然還 有就是暴露與通道和通道偵聽器裡類似的一個查詢機制。代碼如下所示:
public interface IChannelFactory : ICommunicationObject {
T GetProperty<T>() where T: class;
}
IChannelFactory<TChannel>接口
所有的通道工廠也都實現了IChannelFactory<TChannel>接口。這個接 口繼承自IChannelFactory,所以它比IChannelFactory的用處更廣。 IChannelFactory<TChannel>定義了2個成員,如下所示:
public interface IChannelFactory<TChannel> : IChannelFactory {
TChannel CreateChannel(EndpointAddress to);
TChannel CreateChannel(EndpointAddress to, Uri via);
}
CreateChannel方法包含2個參數。它們是EndpointAddress和Uri類型。在運 行時,這些參數會序列化到消息裡,via參數就是通道要嘗試連接的地址,to是 發送消息的地址。中間可能經過消息的中轉(第2章裡曾經講到)。
ChannelFactoryBase類型
通道工廠簡介繼承了抽象類型ChannelFactoryBase。概念上,它的作用與通 道偵聽器裡使用的ChannelListenerBase類型一樣。換句話說, ChannelListenerBase類型也提供了一種自定義打開、關閉、發送和接受消息超 時屬性的方式。它的對象模型如下所示:
public abstract class ChannelFactoryBase : ChannelManagerBase,
IChannelFactory {
protected ChannelFactoryBase();
protected ChannelFactoryBase(IDefaultCommunicationTimeouts timeouts);
// IChannelFactory implementation
public virtual T GetProperty<T>() where T: class;
// CommunicationObject implementation
protected override void OnAbort();
protected override IAsyncResult OnBeginClose(TimeSpan timeout,
AsyncCallback callback,
Object state);
protected override void OnClose(TimeSpan timeout);
protected override void OnEndClose(IAsyncResult result);
protected override TimeSpan DefaultCloseTimeout { get; }
protected override TimeSpan DefaultOpenTimeout { get; }
// ChannelManagerBase implementation
protected override TimeSpan DefaultReceiveTimeout { get; }
protected override TimeSpan DefaultSendTimeout { get; }
}
ChannelFactoryBase<TChannel>類型
ChannelFactoryBase<TChannel>類型繼承了ChannelFactoryBase 類型 ,而且實現了IChannelFactory<TChannel>接口。它也是通道工廠類型的 基類。更進一步說,這個類型維護和控制通道的創建狀態。(想一下本章前面“ 通道管理器的概念”一節。)ChannelFactoryBase<TChannel>的對象模型 如下:
public abstract class ChannelFactoryBase<TChannel> : ChannelFactoryBase,
IChannelFactory<TChannel> {
// calls the other constructor, passing null as argument
protected ChannelFactoryBase();
// creates an object that manages the channels
protected ChannelFactoryBase(IDefaultCommunicationTimeouts timeouts);
// IChannelFactory<TChannel> implementation
public TChannel CreateChannel(EndpointAddress address);
public TChannel CreateChannel(EndpointAddress address, Uri via);
// Extensibility point for IChannelFactory<TChannel> implementation
protected abstract TChannel OnCreateChannel(EndpointAddress address, Uri via);
// CommunicationObject implementation: changes state
// of the channels it has created
protected override void OnAbort();
protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback,
object state);
protected override void OnClose(TimeSpan timeout);
protected override void OnEndClose(IAsyncResult result);
// helper method that checks the State to see if the
// channel factory can create channels (CommunicationState.Opened)
protected void ValidateCreateChannel();
}
ChannelFactoryBase<TChannel>的構造函數實例化了一個對象,這個 對象可以保存工廠裡創建的通道對象的引用。當 ChannelFactoryBase<TChannel> 對象關閉或者終止的時候,這個對象可 以確保引用的通道狀態機與ChannelFactoryBase<TChannel>對象狀態一致 。這些代碼確保狀態改變發生在ChannelFactoryBase<TChannel> 裡 CommunicationObject的實現裡。
ChannelFactoryBase<TChannel>另外一個有趣的地方就是 ValidateCreateChannel 方法。這個方法僅僅是為了確保對象的狀態是 CommunicationState.Opened。如果狀態不是,這個方法就會拋出一個 InvalidOperationException異常。兩個CreateChannel方法都會調用這個方法來 確保通道工廠處於正確的狀態。
創建自定義通道工廠
既然已經學習了通道工廠裡重要的相關類型,現在我們來創建一個自定義通 道工廠,繼續完成我們的DelegatorChannel例子。和前面的 DelegatorChannelListener<TShape>例子類似,我們的通道工廠必須可以 創建任何形狀的通道。因此,我們的通道工廠必須使用泛型,如下所示:
internal sealed class DelegatorChannelFactory<TShape> :
ChannelFactoryBase<TShape> {
// reference the next channel factory in the stack
IChannelFactory<TShape> _innerFactory;
// the String to print to the console
String _consolePrefix = "FACTORY: DelegatorChannelFactory";
// ctor that builds the next channel factory in the stack,
// then assigns the _innerFactory member variable
internal DelegatorChannelFactory(BindingContext context) {
PrintHelper.Print(_consolePrefix, "ctor");
this._innerFactory = context.BuildInnerChannelFactory<TShape>();
}
// instantiates and returns a DelegatorChannel that
// references another channel
private TShape WrapChannel(TShape innerChannel) {
if(innerChannel == null) {
throw new ArgumentNullException("innerChannel cannot be null",
"innerChannel");
}
if(typeof(TShape) == typeof(IOutputChannel)) {
return (TShape)(Object) new DelegatorOutputChannel<IOutputChannel>
(this, (IOutputChannel)innerChannel, "SEND");
}
if(typeof(TShape) == typeof(IRequestChannel)) {
return (TShape)(Object) new DelegatorRequestChannel
(this, (IRequestChannel)innerChannel, "SEND");
}
if(typeof(TShape) == typeof(IDuplexChannel)) {
return (TShape)(Object) new DelegatorDuplexChannel
(this, (IDuplexChannel)innerChannel, "SEND");
}
if(typeof(TShape) == typeof(IOutputSessionChannel)) {
return (TShape)(Object) new DelegatorOutputSessionChannel
(this, (IOutputSessionChannel)innerChannel, "SEND");
}
if(typeof(TShape) == typeof(IRequestSessionChannel)) {
return (TShape)(Object) new DelegatorRequestSessionChannel
(this, (IRequestSessionChannel)innerChannel, "SEND");
}
if(typeof(TShape) == typeof(IDuplexSessionChannel)) {
return (TShape)(Object) new DelegatorDuplexSessionChannel
(this, (IDuplexSessionChannel)innerChannel, "SEND");
}
// cannot wrap this channel
throw new ArgumentException(String.Format("invalid channel shape
passed:{0}", innerChannel.GetType()));
}
// uses the _innerFactory member variable to build a channel
// then wraps it and returns the wrapped channel
protected override TShape OnCreateChannel(EndpointAddress address,
Uri via) {
// create and return the channel
PrintHelper.Print(_consolePrefix, "OnCreateChannel");
TShape innerChannel = this._innerFactory.CreateChannel (address, via);
return WrapChannel(innerChannel);
}
protected override IAsyncResult OnBeginOpen(TimeSpan timeout,
AsyncCallback callback,
Object state) {
PrintHelper.Print(_consolePrefix, "OnBeginChannel");
return this._innerFactory.BeginOpen(timeout, callback, state);
}
protected override void OnAbort() {
base.OnAbort();
PrintHelper.Print(_consolePrefix, "OnAbort");
}
protected override void OnClose(TimeSpan timeout) {
base.OnClose(timeout);
PrintHelper.Print(_consolePrefix, "OnClose");
}
protected override void OnEndOpen(IAsyncResult result) {
PrintHelper.Print(_consolePrefix, "OnEndOpen");
this._innerFactory.EndOpen(result);
}
protected override void OnOpen(TimeSpan timeout) {
PrintHelper.Print(_consolePrefix, "OnOpen");
this._innerFactory.Open(timeout);
}
public override T GetProperty<T>() {
PrintHelper.Print(_consolePrefix, "GetProperty<" + typeof(T).Name +
">");
return this._innerFactory.GetProperty<T>();
}
}
定義上來看,DelegatorChannelFactory<TShape>與 DelegatorChannelListener<TShape> 很相似,它定義了一個私有的 WrapChannel方法,可以把一個通道包裝為特定的形狀,然後返回。當然也定義 了另外幾個方法,這些方法可以把狀態轉換傳遞給成員變量innerFactory的。
本章小結
WCF 類型通過通道工廠和通道偵聽器來創建通道。通道偵聽器負責偵聽可用 的連接。通道工廠和通道偵聽器的架構模型與伯克利的Sockets API十分相似, 和通道一樣,通道工廠和通道偵聽器也是在運行時組裝到堆棧的,並且堆棧裡的 每個通道偵聽器或通道工廠都負責創建一個通道。另外就是傳輸通道工廠或者通 道偵聽器必須位於堆棧的底部。此外,用戶代碼不能直接實例化通道偵聽器和通 道工廠。這些工作有BindingElement完成。Binding和BindingElement對象會在 下一章裡講到,而且作為總結部分,你會看到我們定義的DelegatorChannel 通 道、以及DelegatorChannelListener<TShape> 和 DelegatorChannelFactory<TShape>類型。