3.4.2 信道工厂(Channel Factory)
信道工厂是信道管理器在客户端的别名,这是因为信道工厂的作用就是单纯地创建用于发送请求和接收回复的信道。我们先来看看与信道工厂相关的一些接口和基类的定义。
信道工厂相关的编程接口
WCF为信道监听器定义了两个接口:IChannelListener和IChannelListener<TChannel>。与之相对地,信道工厂也具有两个接口:IChannelFactory和IChannelFactory<TChannel>。由于信道工厂的目的就是创建信道,所以IChannelFactory和IChannelFactory<TChannel>的定义显得格外简洁。两个重载的CreateChannel通过目标终结点的地址(逻辑地址和物理地址)创建相应的信道栈。
public interface IChannelFactory : ICommunicationObject { T GetProperty<T>() where T : class; } public interface IChannelFactory<TChannel> : IChannelFactory, ICommunicationObject { TChannel CreateChannel(EndpointAddress to); TChannel CreateChannel(EndpointAddress to, Uri via); }
除了上面的两个接口之外,WCF还定义了两个抽象基类:ChannelFactoryBase和ChannelFactoryBase<TChannel>。ChannelFactoryBase继承自信道管理基类ChannelManagerBase,而ChannelFactoryBase<TChannel>又继承自ChannelFactoryBase。基类继承和接口实现关系体现在图3-14所示的类图中。
图3-14 信道工厂接口口与基类
public abstract class ChannelFactoryBase : ChannelManagerBase, IChannelFactory, ICommunicationObject { //省略成员 } public abstract class ChannelFactoryBase<TChannel> : ChannelFactoryBase, IChannelFactory<TChannel>, IChannelFactory, ICommunicationObject { //省略成员 }
案例演示:如何自定义信道工厂
上面的案例为自定义的数据报回复信道和会话双工信道创建了信道监听器,接下来的任务就是为自定义的数据报请求信道(SimpleRequestChannel)和会话双工信道(SimpleDuplex-SessionChannel)创建信道工厂。
1.创建数据报信道工厂
接下来,我们为前面创建的SimpleRequestChannel创建一个信道工厂:SimpleDatagram-ChannelFactory<TChannel>。SimpleDatagramChannelFactory<TChannel>直接继承自抽象基类ChannelFactoryBase<TChannel>。
字段_innerChannelFactory表示后一个信道工厂对象,在构造函数中,通过传入的BindingContext创建。OnCreateChannel是核心方法,实现了真正的信道创建,在这里我们创建了自定义的信道:SimpleRequestChannel。构建SimpleRequestChannel的InnerChannel通过_innerChannelFactory的CreateChannel方法创建。对于其他的方法(OnOpen、OnBeginOpen和OnEndOpen等),在输出相关信息后,调用_innerChannelFactory相应的方法。
public class SimpleDatagramChannelFactory<TChannel> : ChannelFactoryBase<TChannel> { public IChannelFactory<TChannel> _innerChannelFactory; public SimpleDatagramChannelFactory(BindingContext context) { PrintHelper.Print(this, "SimpleDatagramChannelFactory"); this._innerChannelFactory = context.BuildInnerChannelFactory <TChannel>(); } protected override TChannel OnCreateChannel(EndpointAddress address,Uri via) { PrintHelper.Print(this, "OnCreateChannel"); IRequestChannel innerChannel = this._innerChannelFactory. CreateChannel(address, via) as IRequestChannel; SimpleRequestChannel. channel = new SimpleRequestChannel.(this, innerChannel); return (TChannel)(object)channel; } protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state) { PrintHelper.Print(this, "OnBeginOpen"); return this._innerChannelFactory.BeginOpen(timeout, callback, state); } protected override void OnEndOpen(IAsyncResult result) { PrintHelper.Print(this, "OnEndOpen"); this._innerChannelFactory.EndOpen(result); } protected override void OnOpen(TimeSpan timeout) { PrintHelper.Print(this, "OnOpen"); this._innerChannelFactory.Open(timeout); } }
2.创建会话信道工厂
会话信道信道工厂与数据报信道工厂的定义很类似。在下面的代码中,我们为前面创建的会话信道SimpleDuplexSessionChannel创建了信道工厂:SimpleSessionChannelFactory<TChannel>。在OnCreateChannel方法中,SimpleDuplexSessionChannel被创建出来,SimpleDuplexSessionChannel的InnerChannel通过BindingContext创建。此外,GetProperty<T>被重写。
using System; using System.ServiceModel; using System.ServiceModel.Channels; namespace Artech.CustomChannels { public class SimpleSessionChannelFactory<TChannel> : ChannelFactoryBase<TChannel> { public IChannelFactory<TChannel> _innerChannelFactory; public SimpleSessionChannelFactory(BindingContext context) { PrintHelper.Print(this, "SimpleSessionChannelFactory"); this._innerChannelFactory = context. BuildInnerChannelFactory<TChannel>(); } protected override TChannel OnCreateChannel(EndpointAddress address, Uri via) { PrintHelper.Print(this, "OnCreateChannel"); IDuplexSessionChannel innerChannel = this._innerChannelFactory. CreateChannel(address, via) as IDuplexSessionChannel; SimpleDuplexSessionChannel channel = new SimpleDuplexSessionChannel(this, innerChannel); return (TChannel)(object)channel; } protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state) { PrintHelper.Print(this, "OnBeginOpen"); return this._innerChannelFactory.BeginOpen(timeout, callback, state); } protected override void OnEndOpen(IAsyncResult result) { PrintHelper.Print(this, "OnEndOpen"); this._innerChannelFactory.EndOpen(result); } protected override void OnOpen(TimeSpan timeout) { PrintHelper.Print(this, "OnOpen"); this._innerChannelFactory.Open(timeout); } public override T GetProperty<T>() { return this._innerChannelFactory.GetProperty<T>(); } } }