您的位置:首页 > 其它

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

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

创建基类型

因为所有的通道都要使用通道状态机,并且每个通道必须保留堆栈里下一个通道实例的引用,因此把这些属性的声明放在一个基类里比较合理。所有的通道类型都会继承自这个基类型,所以把基类型定义为泛型更加合适。考虑到这些需求,我把基类型命名为DelegatorChannelBase<TShape>,TShape必须是一个引用类型,而且继承自IChannel。(记住所有的通道类型都继承自IChannel。)DelegatorChannelBase<TShape>的是ChannelBase的子类型,因为这样它就会使用公共的状态机,并且可以实现Binding 的超时属性。DelegatorChannelBase<TShape>的初始定义如下:




internal class DelegatorChannelBase<TShape> : ChannelBase




where TShape : class, IChannel {


// implementation not shown yet


}

添加构造函数

DelegatorChannelBase<TShape>对象不能放在堆栈的底部。换句话说,DelegatorChannelBase<TShape>对象必须拥有一个通道对象的引用,而且泛型类型表示的是通道形状,我们会把泛型类型作为构造函数的参数。当然构造函数还需要一个通道工厂的引用。当然,一个原因就是为了便于实现绑定的(time-out)超时属性。另外一个原因就是为了在创建通道完毕的时候可以通知一下通道工厂。你会在第7章里看到更多内容。基类的构造函数定义如下:


internal class DelegatorChannelBase<TShape> : ChannelBase


where TShape : class, IChannel {


private TShape _innerChannel; // reference the next channel in the stack


private String _source; // part of the String to print to the console




protected DelegatorChannelBase(ChannelManagerBase channelManagerBase,


TShape innerChannel,


String source) : base(channelManagerBase){


if(innerChannel == null) {


throw new ArgumentNullException("DelegatorChannelBase requires a non-null channel.",
"innerChannel");


}


// set part of the String to print to console


_source = String.Format("{0} CHANNEL STATE CHANGE: DelegatorChannelBase", source);


// set the reference to the next channel


_innerChannel = innerChannel;


}


// other implementation not shown yet


}


注意_innerChannel和_source成员变量。像注释说的,这些成员变量是为了存储下一个通道的引用和要打印的字符。构造函数的第一个参数是ChannelManagerBase类型。ChannelManagerBase的引用通过ChannelBase构造函数存储起来。




添加状态机


因为DelegatorChannelBase<TShape>继承自抽象类型ChannelBase,并且ChannelBase继承自抽象类型CommunicationObject但没有实现CommunicationObject里定义的成员,因此DelegatorChannelBase<TShape>类型必须实现这些抽象成员。因此DelegatorChannelBase<TShape>里的所有状态转换必须传播到堆栈里的其它通道,我们的状态转换方法委托会调用innerChannel通道变量,如下所示:




internal class DelegatorChannelBase<TShape> : ChannelBase


where TShape : class, IChannel {


private TShape _innerChannel; // reference to the next channel


private String _source; // part of the String to output


// provide the _innerChannel to derived types


protected TShape InnerChannel {


get { return _innerChannel; }


}


protected DelegatorChannelBase(ChannelManagerBase channelManagerBase,


TShape innerChannel,


String source) : base(channelManagerBase){


if(innerChannel == null) {


throw new ArgumentNullException("DelegatorChannelBase requires a non-null channel.",
"innerChannel");


}


// set part of the String to print to console


_source = String.Format("{0} CHANNEL STATE CHANGE: DelegatorChannelBase", source);


// set the reference to the next channel


_innerChannel = innerChannel;


}


// IChannel implementation


public override T GetProperty<T>() {


return this._innerChannel.GetProperty<T>();


}


CommunicationObject members#region CommunicationObject members


protected override void OnAbort() {


PrintHelper.Print(_source, "OnAbort");


this._innerChannel.Abort();


}


protected override IAsyncResult OnBeginClose(TimeSpan timeout,


AsyncCallback callback,


Object state) {


// output that the method was called


PrintHelper.Print( _source, "OnBeginClose");


// delegate the call to the next channel


return this._innerChannel.BeginClose(timeout, callback, state);


}


protected override IAsyncResult OnBeginOpen(TimeSpan timeout,


AsyncCallback callback,


Object state) {


// output that the method was called


PrintHelper.Print(_source, "OnBeginOpen");


// delegate the call to the next channel


return this._innerChannel.BeginOpen(timeout, callback, state);


}


protected override void OnClose(TimeSpan timeout) {


// output that the method was called


PrintHelper.Print(_source, "OnClose");


// delegate the call to the next channel


this._innerChannel.Close(timeout);


}


protected override void OnEndClose(IAsyncResult result) {


// output that the method was called


PrintHelper.Print(_source, "OnEndClose");


// delegate the call to the next channel


this._innerChannel.EndClose(result);


}


protected override void OnEndOpen(IAsyncResult result) {


// output that the method was called


PrintHelper.Print(_source, "OnEndOpen");


// delegate the call to the next channel


this._innerChannel.EndOpen(result);


}


protected override void OnOpen(TimeSpan timeout) {


// output that the method was called


PrintHelper.Print(_source, "OnOpen");


// delegate the call to the next channel


this._innerChannel.Open(timeout);


}


#endregion


}
每个状态转换方法(OnAbort、OnBeginClose、OnBeginOpen、OnClose、OnEndClose、OnEndOpen和OnOpen)都会调用通道上对应的状态转换方法。每个状态转换方法也可以调用PrintHelper类型上的静态方法Print。PrintHelper类型只做在控制台窗口上打印字符的工作。

创建数据报通道

既然我们已经定义了通道的基类型,现在就定义数据报消息交换模式的通道吧。因为数据报发送通道必须继承IInputChannel接口,接收通道必须继承IOutputChannel接口,所以我们需要DelegatorChannelBase<TShape>来继承这2个接口并实现他们。因为数据报接口被用作双工通信的接口,同时也会做会双工会话通道接口,所以我们把数据报通道定义为泛型。

注释:我们会从接收者开始,然后定义发送者。为了简明扼要,我就不把所有的代码都贴出来,而是着重展示代码里的实现模式。

数据报接收通道

数据报接收通道继承自DelegatorChannelBase<TShape>类型并且实现了IInputChannel接口。和DelegatorChannelBase<TShape>一样,我们的数据报接收通道也会被定义为泛型类型,因此允许被双工通道复用,同样也可以被数据报和双工变量成员使用。因为这些需求,数据报接收通道命名为DelegatorInputChannel<TShape>,如下所示:


internal class DelegatorInputChannel<TShape> :


DelegatorChannelBase<TShape>, IInputChannel


where TShape:class, IInputChannel {


// implementation not shown


}
DelegatorInputChannel<TShape>构造函数必须调用基类的构造函数,设置输出String的值,并且调用PrintHelper.Print方法,如下所示:


internal class DelegatorInputChannel<TShape> :


DelegatorChannelBase<TShape>, IInputChannel


where TShape:class, IInputChannel {


private String _source; // store the String to output


internal DelegatorInputChannel(ChannelManagerBase channelManagerBase,


TShape innerChannel,


String source) : base(channelManagerBase,


innerChannel,


source) {


// assign the name and generic parameter to the String


_source = String.Format("{0} CHANNEL: DelegatorInputChannel<{1}>",


source,


typeof(TShape).Name);


// output that the method was called


PrintHelper.Print(_source, "ctor");


}


// other implementation not shown


}
下面我们需要实现IInputChannel接口,为了简略起见,我只列举三个成员:




public IAsyncResult BeginReceive(TimeSpan timeout,


AsyncCallback callback,


Object state) {


// output that the method was called


PrintHelper.Print(_source, "BeginReceive");


// delegate the call to the next channel


return this.InnerChannel.BeginReceive(timeout, callback, state);


}


public IAsyncResult BeginReceive(AsyncCallback callback, Object state) {


// output that the method was called


PrintHelper.Print(_source, "BeginReceive");


// delegate the call to the next channel


return this.InnerChannel.BeginReceive(callback, state);


}


public IAsyncResult BeginTryReceive(TimeSpan timeout,


AsyncCallback callback,


Object state) {


// output that the method was called


PrintHelper.Print(_source, "BeginTryReceive");


// delegate the call to the next channel


return this.InnerChannel.BeginTryReceive(timeout, callback, state);


}


DelegatorInputChannel<TShape>类型只有在其它成员定义结束以后才会完整(EndReceive、EndTryReceive、EndWaitForMessage、 LocalAddress、Receive、TryReceive和WaitForMessage)。




数据报发送通道


数据报发送通道与接收通道很相似,区别仅仅在于它实现了IOutputChannel接口。为了避免重复,我们会给出这个类型定义,而DelegatorInputChannel<TShape>实现则交给读者来做:




internal class DelegatorOutputChannel<TShape> :


DelegatorChannelBase<TShape>, IOutputChannel where


TShape: class, IOutputChannel {


private String _source; // store the String to output


internal DelegatorOutputChannel(ChannelManagerBase channelManagerBase,


TShape innerChannel,


String source) : base(channelManagerBase,


innerChannel,


source) {


_source = String.Format("{0} CHANNEL: DelegatorOutputChannel<{1}>", source,


typeof(TShape).Name);


// output that the method was called


PrintHelper.Print(_source, "ctor");


}


IOutputChannel Members#region IOutputChannel Members


public IAsyncResult BeginSend(Message message,


TimeSpan timeout,


AsyncCallback callback,


Object state) {


// output that the method was called


PrintHelper.Print(_source, "BeginSend");


// delegate the call to the next channel


return this.InnerChannel.BeginSend(message, timeout, callback, state);


}


public IAsyncResult BeginSend(Message message, AsyncCallback callback, object state) {


// output that the method was called


PrintHelper.Print(_source, "BeginSend");


// delegate the call to the next channel


return this.InnerChannel.BeginSend(message, callback, state);


}


public void EndSend(IAsyncResult result) {


// output that the method was called


PrintHelper.Print(_source, "EndSend");


// delegate the call to the next channel


this.InnerChannel.EndSend(result);


}


public EndpointAddress RemoteAddress {


get {


// output that the method was called


PrintHelper.Print(_source, "RemoteAddress");


// delegate the call to the next channel


return this.InnerChannel.RemoteAddress; }


}


public void Send(Message message, TimeSpan timeout) {


// output that the method was called


PrintHelper.Print(_source, "Send");


// delegate the call to the next channel


this.InnerChannel.Send(message, timeout);


}


public void Send(Message message) {


// output that the method was called


PrintHelper.Print(_source, "Send");


// delegate the call to the next channel


this.InnerChannel.Send(message);


}


public Uri Via {


get {


// output that the method was called


PrintHelper.Print(_source, "Via");


// delegate the call to the next channel


return this.InnerChannel.Via;


}


}


#endregion


}双工通道

想一下通道的形状,记得IDuplexChannel接口是IInputChannel 和IOutputChannel的结合体。因为我们已经有了一个类型实现了IInputChannel 和IOutputChannel,所以我们可以服用这个类型作为我们的基类。与IOutputChannel 相比,IInputChannel接口包含更多的成员,所以(没有意外的话)DelegatorInputChannel<TShape>类型会作为我们的双工通信的基类型。
因为双工通道实现了IDuplexChannel接口,我们来调用DelegatorDuplexChannel双工通道,并且在基类里使用IDuplexChannel作为泛型参数,如下所示:


internal class DelegatorDuplexChannel :


DelegatorInputChannel<IDuplexChannel>, IDuplexChannel {


// implementation not shown yet


}Because the DelegatorDuplexChannel is very similar to the DelegatorInputChannel<TShape> type definition, I will show only part of the type definition here: [/code]
DelegatorDuplexChannel与DelegatorInputChannel<TShape>的定义很类似,我这里只展示类型定义部分:


internal class DelegatorDuplexChannel :


DelegatorInputChannel<IDuplexChannel>, IDuplexChannel {


private String _source; // store the String to output


internal DelegatorDuplexChannel(ChannelManagerBase channelManagerBase,


// use IDuplexSession as the 2nd parameter


IDuplexChannel innerChannel,


String source) : base(channelManagerBase,


innerChannel,


source) {


_source = String.Format("{0} CHANNEL: DelegatorDuplexChannel", source);


PrintHelper.Print(_source, "ctor");


}


IOutputChannel Members#region IOutputChannel Members


public IAsyncResult BeginSend(Message message,


TimeSpan timeout,


AsyncCallback callback,


Object state) {


PrintHelper.Print(_source, "BeginSend");


return this.InnerChannel.BeginSend(message, timeout, callback, state);


}


// other IOutputChannel Members omitted for brevity


#endregion


}


双工会话通道


从对象模型的角度来看,会话通道形状与非会话通道只有一些细微的差别。例如,IDuplexSessionChannel是IDuplexChannel和 ISessionChannel<IDuplexSession>的结合体。因为我们已有有了一个DelegatorDuplexChannel类型定义(它实现了IDuplexChannel接口),创建一个会话通道仅仅是一个继承DelegatorDuplexChannel并实现IDuplexSessionChannel接口的问题,如下所示:




internal sealed class DelegatorDuplexSessionChannel :


DelegatorDuplexChannel, IDuplexSessionChannel {


private IDuplexSessionChannel _innerSessionChannel; // reference the next


// sessionful channel


private String _source; // store the String to output


internal DelegatorDuplexSessionChannel(ChannelManagerBase


channelManagerBase, IDuplexSessionChannel innerChannel, String source)


: base(channelManagerBase, innerChannel, source) {


_source = String.Format("{0} CHANNEL: DelegatorDuplexSessionChannel",


source);


PrintHelper.Print(_source, "ctor");


// assign the reference to the next sessionful channel


this._innerSessionChannel = innerChannel;


}


// IDuplexSessionChannel member that is not defined in IDuplexChannel


public IDuplexSession Session {


get {


PrintHelper.Print(_source, "Session");


return this._innerSessionChannel.Session; }


}


}
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程序里使用我们的自定义通道。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐