[原创]WCF后续之旅(2): 如何对Channel Layer进行扩展——创建自定义Channel

上一篇文章中,我们通过一个直接借助BasicHttpBinding对象实现Client和Server端进行通信的例子,对WCF channel layer进行了一个大致上的介绍。由此引出了一些列通信相关的概念和对象,比如Channel,Output channel, Input channel,Request channel, Reply Channel,Duplex channel, Channel Shape,Channel manager,Channel factory, Channel listener, Binding element 等。通过这些元素,我们很容易地实现对WCF channel layer进行扩展。

对channel layer进行扩展一般适用于当你的需求通过现有的Binding,或者channel不能实现,而需要自定义一些channel来实现你所需的功能。不如现在的WCF系统定义的Channel中没有实现对Message body的压缩功能。你可以就需要将此功能定义到一个custom channel中,然后将其注入到channel stack中。一般来说,仅仅创建custom channel是不够的,因为在runtime, channel是通过Channel manager进行创建的,所以你需要创建对应的Channel factory(如何对发送方进行扩展)或者Channel listener(如果对接受方进行扩展)。而Channel factory和channel listener最终又是通过Binding element进行创建的,所以你还需要创建相应的Binding element。(Binding element=〉Channel factory&Channel listener=>Channel

在本章节中,我们将继续讨论WCF channel layer。我们将通过如何创建和应用custom channel来介绍channel layer一些知识。

1、ICommunicationObject 和 CommunicationObject

我们知道WCF channel layer的绝大部分对象,比如Channel,Channel factory,Channel listener,从功能上讲都是用于通信(Communication)的对象,对传统的communication object,比如socket,他们往往都具有通过状态和状态转化规则(状态机:State machine)。这些状态包括Creating、Created、Opening、Opened、Closing、Closed等等。为了统一管理这些状态和状态之间的转化,WCF定义个一个特殊的Interface:ICommunicationObject

publicinterface ICommunicationObject
{
// Events
event EventHandler Closed;
event EventHandler Closing;
event EventHandler Faulted;
event EventHandler Opened;
event EventHandler Opening;

// Methods
void Abort();
IAsyncResult BeginClose(AsyncCallback callback,
object state);
IAsyncResult BeginClose(TimeSpan timeout, AsyncCallback callback,
object state);
IAsyncResult BeginOpen(AsyncCallback callback,
object state);
IAsyncResult BeginOpen(TimeSpan timeout, AsyncCallback callback,
object state);
void Close();
void Close(TimeSpan timeout);
void EndClose(IAsyncResult result);
void EndOpen(IAsyncResult result);
void Open();
void Open(TimeSpan timeout);

// Properties
CommunicationState State { get; }
}

ICommunicationObject定义了3种成员:

  • Property:State, 得到当前的状态,返回值是一个CommunicationState 枚举。
  • Method:同步、异步Open和Close方法。
  • Event:通过注册这些状态相关的Event,当时对象转化到对应的状态时执行相应操作。

WCF定义了一个abstract class: CommunicationObject直接实现了该Interface。CommunicationObject的实现统一的State machine。WCF channel layer的很多的class都直接或者间接的继承了这个class。你也可以让你的class继承该class。当你让你自己的class继承CommunicationObject的时候,在override 掉base相应的method的时候,强烈建议你先调用base对应的方法,CommunicationObject会帮你进行相应的State转换和触发相应的事件。

2. Channel 和Channel Shape

上一篇文章中,我们讨论过了。在不同的消息交换模式(MEP)中,发送方和接受方的Channel扮演的角色是不相同的。我们并把这种不同MEP中消息交互双方Channel的结构差异表述为Channel shape。我们有四种不同的Channel shape:Datagram、Request/reply、Duplex和P2P。不同Channel shape中Channel的结构性差性通过实现不同的Channel interface来体现。

对于Datagram channel shape,采用了One-way的MEP。发送方的channel 必须实现IOutputChannel interface。该Interface的方法成员主要集中在用于发送message的Send方法(同步/异步):

publicinterface IOutputChannel : IChannel, ICommunicationObject
{
// Methods
IAsyncResult BeginSend(Message message, AsyncCallback callback, object state);
IAsyncResult BeginSend(Message message, TimeSpan timeout, AsyncCallback callback,
object state);
void EndSend(IAsyncResult result);
void Send(Message message);
void Send(Message message, TimeSpan timeout);

// Properties
EndpointAddress RemoteAddress { get; }
Uri Via
{ get; }
}

与之相应是IInputChannel inteface,该Interface用于Datagram channel shape中接收方的channel定义。其主要方法成员主要集中在用于接收Message的Receive方法(同步/异步):

public interface IInputChannel : IChannel, ICommunicationObject
{
// Methods
IAsyncResult BeginReceive(AsyncCallback callback, object state);
IAsyncResult BeginReceive(TimeSpan timeout, AsyncCallback callback,
object state);
IAsyncResult BeginTryReceive(TimeSpan timeout, AsyncCallback callback,
object state);
IAsyncResult BeginWaitForMessage(TimeSpan timeout, AsyncCallback callback,
object state);
Message EndReceive(IAsyncResult result);
bool EndTryReceive(IAsyncResult result, out Message message);
bool EndWaitForMessage(IAsyncResult result);
Message Receive();
Message Receive(TimeSpan timeout);
bool TryReceive(TimeSpan timeout, out Message message);
bool WaitForMessage(TimeSpan timeout);

// Properties
EndpointAddress LocalAddress { get; }
}

注:无论对于同步或者异步方法,一般由两个重载,一个接收一个TimeSpan 作为参数,表是Send或者Receive允许的时间范围。而另一个没有该参数的方式,不不是建议你使用一个无限的TimeSpan,而是使用一个可配置的默认时间段(实际上是Binding对象对应的属性)

不同于Datagram channel shape,Request/request channel shape下交互双方的Channel具有不同的行为。发送方的Channel实现IRequestChannel。该interface的方面成员主要集中在一些用于向接收方进行请求的Request方法(同步/异步):上面。

publicinterface IRequestChannel : IChannel, ICommunicationObject
{
// Methods
IAsyncResult BeginRequest(Message message, AsyncCallback callback, object state);
IAsyncResult BeginRequest(Message message, TimeSpan timeout, AsyncCallback callback,
object state);
Message EndRequest(IAsyncResult result);
Message Request(Message message);
Message Request(Message message, TimeSpan timeout);

// Properties
EndpointAddress RemoteAddress { get; }
Uri Via
{ get; }
}

同理,对于接收方的IReplyChannel则主要定义了一些用于Reply的方法:

public interface IReplyChannel : IChannel, ICommunicationObject
{
// Methods
IAsyncResult BeginReceiveRequest(AsyncCallback callback, object state);
IAsyncResult BeginReceiveRequest(TimeSpan timeout, AsyncCallback callback,
object state);
IAsyncResult BeginTryReceiveRequest(TimeSpan timeout, AsyncCallback callback,
object state);
IAsyncResult BeginWaitForRequest(TimeSpan timeout, AsyncCallback callback,
object state);
RequestContext EndReceiveRequest(IAsyncResult result);
bool EndTryReceiveRequest(IAsyncResult result, out RequestContext context);
bool EndWaitForRequest(IAsyncResult result);
RequestContext ReceiveRequest();
RequestContext ReceiveRequest(TimeSpan timeout);
bool TryReceiveRequest(TimeSpan timeout, out RequestContext context);
bool WaitForRequest(TimeSpan timeout);

// Properties
EndpointAddress LocalAddress { get; }
}

而对与Duplex和P2P,消息交互双方使用相同的Channel: Duplex channel。本质上讲, DuplexChannel = OutputChannel + IntputChannel。这一点从IDuplexChannel的定义上就可以看出来:
publicinterface IDuplexChannel : IInputChannel, IOutputChannel, IChannel, ICommunicationObject
{
}

3、创建Custom Channel

为了让大家对WCF channel layer有一个深刻的认识,以及掌握如何有效地对其进行扩展。我在整篇文章中穿插介绍一个具体的Sample:创建一个自定义的channel,以及相关的辅助对象,比如Channel factory、Channel listener和Binding element

这个Sample将基于我们最为常用的Request/Reply channel shape。所以我们需要创建两个Channel,一个是用于发送方的实现了IRequestChannel的Channel,而另一个则是实现了IReplyChannel的用于接收方的Channel。

为了简单起见,在我定义的channel的每个方法仅仅打印出相应的方法名称而已(这样做不但简单,还有的一个好处,那就是当我最后将其应用到具体的Messaging场景中,可以根据控制台打印出来的文字清楚地看清当我们的Channel应用到具体的场景中后先后执行了那些方法)。

我们先来看看实现了IRequestChannel的MyRequestChannel的定义:

namespace Artech.ChannleStackExplore.Channels
{
publicclass MyRequestChannel :ChannelBase, IRequestChannel
{
private IRequestChannel InnerChannel
{get;set;}

public MyRequestChannel(ChannelManagerBase channleManager, IRequestChannel innerChannel)
:
base(channleManager)
{
this.InnerChannel = innerChannel;
}


ChannelBase Members#region ChannelBase Members
protectedoverridevoid OnAbort()
{
Console.WriteLine(
"MyRequestChannel.OnAbort()");
this.InnerChannel.Abort();
}


protectedoverride IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state)
{
Console.WriteLine(
"MyRequestChannel.OnBeginClose()");
returnthis.InnerChannel.BeginClose(timeout, callback, state);
}


protectedoverride IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
{
Console.WriteLine(
"MyRequestChannel.OnBeginOpen()");
returnthis.InnerChannel.BeginOpen(timeout, callback, state);
}


protectedoverridevoid OnClose(TimeSpan timeout)
{
Console.WriteLine(
"MyRequestChannel.OnClose()");
this.Close(timeout);
}


protectedoverridevoid OnEndClose(IAsyncResult result)
{
Console.WriteLine(
"MyRequestChannel.OnEndClose()");
this.InnerChannel.EndClose(result);
}


protectedoverridevoid OnEndOpen(IAsyncResult result)
{
Console.WriteLine(
"MyRequestChannel.OnEndOpen()");
this.InnerChannel.EndOpen(result);
}


protectedoverridevoid OnOpen(TimeSpan timeout)
{
Console.WriteLine(
"MyRequestChannel.OnOpen()");
this.InnerChannel.Open(timeout);
}

#endregion


IRequestChannel Members#region IRequestChannel Members

public IAsyncResult BeginRequest(Message message, TimeSpan timeout, AsyncCallback callback, object state)
{
Console.WriteLine(
"MyRequestChannel.BeginRequest()");
returnthis.BeginRequest(message, timeout, callback, state);
}


public IAsyncResult BeginRequest(Message message, AsyncCallback callback, object state)
{
Console.WriteLine(
"MyRequestChannel.BeginRequest()");
returnthis.InnerChannel.BeginRequest(message, callback, state);
}


public Message EndRequest(IAsyncResult result)
{
Console.WriteLine(
"MyRequestChannel.EndRequest()");
returnthis.InnerChannel.EndRequest(result);
}


public EndpointAddress RemoteAddress
{
get
{
Console.WriteLine(
"MyRequestChannel.RemoteAddress");
returnthis.InnerChannel.RemoteAddress;
}


}


public Message Request(Message message, TimeSpan timeout)
{
Console.WriteLine(
"MyRequestChannel.Request()");
returnthis.InnerChannel.Request(message, timeout);
}


public Message Request(Message message)
{
Console.WriteLine(
"MyRequestChannel.Request()");
returnthis.InnerChannel.Request(message);
}


public Uri Via
{
get
{
Console.WriteLine(
"MyRequestChannel.Via)");
returnthis.InnerChannel.Via;
}


}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值