zoukankan      html  css  js  c++  java
  • 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一些知识。

    一、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

       1: public interface ICommunicationObject
       2: {
       3:     // Events
       4:     event EventHandler Closed;
       5:     event EventHandler Closing;
       6:     event EventHandler Faulted;
       7:     event EventHandler Opened;
       8:     event EventHandler Opening;
       9:  
      10:     // Methods
      11:     void Abort();
      12:     IAsyncResult BeginClose(AsyncCallback callback, object state);
      13:     IAsyncResult BeginClose(TimeSpan timeout, AsyncCallback callback, object state);
      14:     IAsyncResult BeginOpen(AsyncCallback callback, object state);
      15:     IAsyncResult BeginOpen(TimeSpan timeout, AsyncCallback callback, object state);
      16:     void Close();
      17:     void Close(TimeSpan timeout);
      18:     void EndClose(IAsyncResult result);
      19:     void EndOpen(IAsyncResult result);
      20:     void Open();
      21:     void Open(TimeSpan timeout);
      22:  
      23:     // Properties
      24:     CommunicationState State { get; }
      25: } 

    ICommunicationObject定义了3种成员:

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

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

    二、Channel 和Channel Shape

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

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

       1: public interface IOutputChannel : IChannel, ICommunicationObject
       2: {
       3:     // Methods
       4:     IAsyncResult BeginSend(Message message, AsyncCallback callback, object state);
       5:     IAsyncResult BeginSend(Message message, TimeSpan timeout, AsyncCallback callback, object state);
       6:     void EndSend(IAsyncResult result);
       7:     void Send(Message message);
       8:     void Send(Message message, TimeSpan timeout); 
       9:  
      10:     // Properties
      11:     EndpointAddress RemoteAddress { get; }
      12:     Uri Via { get; }
      13: } 

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

       1: public interface IInputChannel : IChannel, ICommunicationObject
       2: {
       3:     // Methods
       4:     IAsyncResult BeginReceive(AsyncCallback callback, object state);
       5:     IAsyncResult BeginReceive(TimeSpan timeout, AsyncCallback callback, object state);
       6:     IAsyncResult BeginTryReceive(TimeSpan timeout, AsyncCallback callback, object state);
       7:     IAsyncResult BeginWaitForMessage(TimeSpan timeout, AsyncCallback callback, object state);
       8:     Message EndReceive(IAsyncResult result);
       9:     bool EndTryReceive(IAsyncResult result, out Message message);
      10:     bool EndWaitForMessage(IAsyncResult result);
      11:     Message Receive();
      12:     Message Receive(TimeSpan timeout);
      13:     bool TryReceive(TimeSpan timeout, out Message message);
      14:     bool WaitForMessage(TimeSpan timeout); 
      15:  
      16:     // Properties
      17:     EndpointAddress LocalAddress { get; }
      18: }

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

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

       1: public interface IRequestChannel : IChannel, ICommunicationObject
       2: {
       3:     // Methods
       4:     IAsyncResult BeginRequest(Message message, AsyncCallback callback, object state);
       5:     IAsyncResult BeginRequest(Message message, TimeSpan timeout, AsyncCallback callback, object state);
       6:     Message EndRequest(IAsyncResult result);
       7:     Message Request(Message message);
       8:     Message Request(Message message, TimeSpan timeout); 
       9:  
      10:     // Properties
      11:     EndpointAddress RemoteAddress { get; }
      12:     Uri Via { get; }
      13: } 

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

       1: public interface IReplyChannel : IChannel, ICommunicationObject
       2: {
       3:     // Methods
       4:     IAsyncResult BeginReceiveRequest(AsyncCallback callback, object state);
       5:     IAsyncResult BeginReceiveRequest(TimeSpan timeout, AsyncCallback callback, object state);
       6:     IAsyncResult BeginTryReceiveRequest(TimeSpan timeout, AsyncCallback callback, object state);
       7:     IAsyncResult BeginWaitForRequest(TimeSpan timeout, AsyncCallback callback, object state);
       8:     RequestContext EndReceiveRequest(IAsyncResult result);
       9:     bool EndTryReceiveRequest(IAsyncResult result, out RequestContext context);
      10:     bool EndWaitForRequest(IAsyncResult result);
      11:     RequestContext ReceiveRequest();
      12:     RequestContext ReceiveRequest(TimeSpan timeout);
      13:     bool TryReceiveRequest(TimeSpan timeout, out RequestContext context);
      14:     bool WaitForRequest(TimeSpan timeout); 
      15:  
      16:     // Properties
      17:     EndpointAddress LocalAddress { get; }
      18: }
    而对与Duplex和P2P,消息交互双方使用相同的Channel:Duplex channel。本质上讲,DuplexChannel = OutputChannel + IntputChannel。这一点从IDuplexChannel的定义上就可以看出来:
       1: public interface IDuplexChannel : IInputChannel, IOutputChannel, IChannel, ICommunicationObject
       2: {
       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的定义:

       1: namespace Artech.ChannleStackExplore.Channels
       2: {
       3:     public class MyRequestChannel :ChannelBase, IRequestChannel
       4:     {
       5:         private IRequestChannel InnerChannel
       6:         {get;set;} 
       7:  
       8:         public MyRequestChannel(ChannelManagerBase channleManager, IRequestChannel innerChannel)
       9:             : base(channleManager)
      10:         {
      11:             this.InnerChannel = innerChannel;
      12:         } 
      13:  
      14:         #region ChannelBase Members
      15:         protected override void OnAbort()
      16:         {
      17:             Console.WriteLine("MyRequestChannel.OnAbort()");
      18:             this.InnerChannel.Abort();
      19:         } 
      20:  
      21:         protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state)
      22:         {
      23:             Console.WriteLine("MyRequestChannel.OnBeginClose()");
      24:             return this.InnerChannel.BeginClose(timeout, callback, state);
      25:         } 
      26:  
      27:         protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
      28:         {
      29:             Console.WriteLine("MyRequestChannel.OnBeginOpen()");
      30:             return this.InnerChannel.BeginOpen(timeout, callback, state);
      31:         } 
      32:  
      33:         protected override void OnClose(TimeSpan timeout)
      34:         {
      35:             Console.WriteLine("MyRequestChannel.OnClose()");
      36:             this.Close(timeout);
      37:         } 
      38:  
      39:         protected override void OnEndClose(IAsyncResult result)
      40:         {
      41:             Console.WriteLine("MyRequestChannel.OnEndClose()");
      42:             this.InnerChannel.EndClose(result);
      43:         } 
      44:  
      45:         protected override void OnEndOpen(IAsyncResult result)
      46:         {
      47:             Console.WriteLine("MyRequestChannel.OnEndOpen()");
      48:             this.InnerChannel.EndOpen(result);
      49:         } 
      50:  
      51:         protected override void OnOpen(TimeSpan timeout)
      52:         {
      53:             Console.WriteLine("MyRequestChannel.OnOpen()");
      54:             this.InnerChannel.Open(timeout);
      55:         }
      56:         #endregion 
      57:  
      58:         #region IRequestChannel Members 
      59:  
      60:         public IAsyncResult BeginRequest(Message message, TimeSpan timeout, AsyncCallback callback, object state)
      61:         {
      62:             Console.WriteLine("MyRequestChannel.BeginRequest()");
      63:             return this.BeginRequest(message, timeout, callback, state);
      64:         } 
      65:  
      66:         public IAsyncResult BeginRequest(Message message, AsyncCallback callback, object state)
      67:         {
      68:             Console.WriteLine("MyRequestChannel.BeginRequest()");
      69:             return this.InnerChannel.BeginRequest(message, callback, state);
      70:         } 
      71:  
      72:         public Message EndRequest(IAsyncResult result)
      73:         {
      74:             Console.WriteLine("MyRequestChannel.EndRequest()");
      75:             return this.InnerChannel.EndRequest(result);
      76:         } 
      77:  
      78:         public EndpointAddress RemoteAddress
      79:         {
      80:             get 
      81:             {
      82:                 Console.WriteLine("MyRequestChannel.RemoteAddress");
      83:                 return this.InnerChannel.RemoteAddress;
      84:             } 
      85:  
      86:         } 
      87:  
      88:         public Message Request(Message message, TimeSpan timeout)
      89:         {
      90:             Console.WriteLine("MyRequestChannel.Request()");
      91:             return this.InnerChannel.Request(message, timeout);
      92:         } 
      93:  
      94:         public Message Request(Message message)
      95:         {
      96:             Console.WriteLine("MyRequestChannel.Request()");
      97:             return this.InnerChannel.Request(message);
      98:         } 
      99:  
     100:         public Uri Via
     101:         {
     102:             get 
     103:             { 
     104:                 Console.WriteLine("MyRequestChannel.Via)");
     105:                 return this.InnerChannel.Via;
     106:             } 
     107:  
     108:         } 
     109:  
     110:         #endregion
     111:     }
     112: } 

    这里唯一需要注意的一点是:在实际的运行环境中,我们的channel仅仅了位于Channel stack的某个环节。该channel和其他的一些channel组成一个管道,这个管道里流淌是Message。所以当一个Channel执行了它相应的操作的时候,需要将message传到下一个channel作进一步处理。所有我们的Channel需要下一个Channel的应用,这个Channel就是我们的InnerChannel字段,该成员在构造函数中指定。  

       1: private IRequestChannel InnerChannel
       2: {get;set;} 
       3:  
       4: public MyRequestChannel(ChannelManagerBase channleManager, IRequestChannel innerChannel)
       5:             : base(channleManager)
       6: {
       7:     this.InnerChannel = innerChannel;
       8: } 

    所以,对于每一个方法,在实现了本Channel的功能之后,只需要调用InnerChannel 的对应的方法即可。 我们再来看看实现了IReplyChannel的MyReplyChannel, 它用于接收方:

       1: namespace Artech.ChannleStackExplore.Channels
       2: {
       3:     public class MyReplyChannel: ChannelBase, IReplyChannel
       4:     {
       5:         private IReplyChannel InnerChannel
       6:         { get; set; } 
       7:  
       8:         public MyReplyChannel(ChannelManagerBase channelManager, IReplyChannel innerChannel):base(channelManager)
       9:         {
      10:             this.InnerChannel = innerChannel;
      11:         } 
      12:  
      13:         ChannelBase Members 
      14:  
      15:         IReplyChannel Members
      16:     }
      17: }

    MyReplyChannel的定义方式和MyRequestChannel完全一样,我们就不用再多说什么了。

    4. 创建Custom Channel Factory & Channel Listener

    通过上一篇文章的介绍,我们知道Channel是通过Channel Manager来创建并管理的,在发送方的Channel Manager被称为Channel Factory对于Channel factory,除了定义了两个Interface之外(IChannelFactoryIChannelFactory<TChannel>

       1: public interface IChannelFactory : ICommunicationObject
       2: {
       3:       // Methods
       4:       T GetProperty<T>() where T : class;
       5: } 
       6:  
       7: public interface IChannelFactory<TChannel> : IChannelFactory, ICommunicationObject
       8: {
       9:     // Methods
      10:     TChannel CreateChannel(EndpointAddress to);
      11:     TChannel CreateChannel(EndpointAddress to, Uri via);
      12: } 

    还定义了两个Base class:ChannelFactoryBase ChannelFactoryBase<TChannel>(限于篇幅,在这里就不多作介绍了)。 为了简单起见,我们上我们的Channel factory继承自ChannelFactoryBase<TChannel>

       1: namespace Artech.ChannleStackExplore.Channels
       2: {
       3:     public class MyChannelFactory<TChannel> : ChannelFactoryBase<TChannel>
       4:     {
       5:         private IChannelFactory<TChannel> InnerChannelFactory
       6:         { get; set; } 
       7:  
       8:         public MyChannelFactory(BindingContext context)
       9:         {
      10:             this.InnerChannelFactory = context.BuildInnerChannelFactory<TChannel>();
      11:         } 
      12:  
      13:         protected override TChannel OnCreateChannel(EndpointAddress address, Uri via)
      14:         {
      15:             Console.WriteLine("MyChannelFactory<TChannel>.OnClose()");
      16:             TChannel innerChannel = this.InnerChannelFactory.CreateChannel(address, via);
      17:             return (TChannel)(object)(new MyRequestChannel(this, innerChannel as IRequestChannel));
      18:         } 
      19:  
      20:         protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
      21:         {
      22:             Console.WriteLine("MyChannelFactory<TChannel>.OnBeginOpen()");
      23:             return this.InnerChannelFactory.BeginOpen(timeout, callback, state);
      24:         } 
      25:  
      26:         protected override void OnEndOpen(IAsyncResult result)
      27:         {
      28:             Console.WriteLine("MyChannelFactory<TChannel>.OnEndOpen()");
      29:             this.InnerChannelFactory.EndOpen(result);
      30:         } 
      31:  
      32:         protected override void OnOpen(TimeSpan timeout)
      33:         {
      34:             Console.WriteLine("MyChannelFactory<TChannel>.OnOpen()");
      35:             this.InnerChannelFactory.Open();
      36:         }
      37:     }
      38: } 

    我们说过,和Channel stack一样,Channel factory仍然是一个stack,原因很简单,一个个的Channel需要相应的channel factory来创建。同Channel一样,当channel factory创建了自己的channel之后需要将接力棒交到下一个Channel factory。不过不通于Channel的是,下一个Channel factory不时在构造函数直接指定的,而是通过构造函数中BindingContext 对象的BuildInnerChannelFactory()创建。

       1: private IChannelFactory<TChannel> InnerChannelFactory
       2: { get; set; } 
       3:  
       4: public MyChannelFactory(BindingContext context)
       5: {
       6:       this.InnerChannelFactory = context.BuildInnerChannelFactory<TChannel>();
       7: } 

    注:BindingContext 的两个最重要的方法就是BuildInnerChannelFactory和BuildInnerChannelListener。前者创建Inner channel factory后者创建Inner Channel listener。

    熟悉了ChannelFactory的定义,大家很自然的想得到ChannelListner的定义(不过ChannelListner的成员比ChannelFactory 要多些):

       1: namespace Artech.ChannleStackExplore.Channels
       2: {
       3:     public class MyChannelListener<TChannel> : ChannelListenerBase<TChannel> where TChannel : class, IChannel
       4:     {
       5:         private IChannelListener<TChannel> InnerChannelListener
       6:         { get; set; } 
       7:  
       8:         public MyChannelListener(BindingContext context)
       9:         {
      10:             this.InnerChannelListener = context.BuildInnerChannelListener<TChannel>();
      11:         } 
      12:  
      13:         protected override TChannel OnAcceptChannel(TimeSpan timeout)
      14:         {
      15:             Console.WriteLine("MyChannelListener<TChannel>.OnAcceptChannel()");
      16:             TChannel innerChannel = this.InnerChannelListener.AcceptChannel(timeout);
      17:             return new MyReplyChannel(this, innerChannel as IReplyChannel) as TChannel;
      18:         } 
      19:  
      20:         protected override IAsyncResult OnBeginAcceptChannel(TimeSpan timeout, AsyncCallback callback, object state)
      21:         {
      22:             Console.WriteLine("MyChannelListener<TChannel>.OnBeginAcceptChannel()");
      23:            return this.InnerChannelListener.BeginAcceptChannel(timeout, callback, state);
      24:         } 
      25:  
      26:         protected override TChannel OnEndAcceptChannel(IAsyncResult result)
      27:         {
      28:             Console.WriteLine("MyChannelListener<TChannel>.OnEndAcceptChannel()");
      29:             TChannel innerChannel = this.InnerChannelListener.EndAcceptChannel(result);
      30:             return new MyReplyChannel(this, innerChannel as IReplyChannel) as TChannel;
      31:         } 
      32:  
      33:         protected override IAsyncResult OnBeginWaitForChannel(TimeSpan timeout, AsyncCallback callback, object state)
      34:         {
      35:             Console.WriteLine("MyChannelListener<TChannel>.OnBeginWaitForChannel()");
      36:             return this.InnerChannelListener.BeginWaitForChannel(timeout, callback, state);
      37:         } 
      38:  
      39:         protected override bool OnEndWaitForChannel(IAsyncResult result)
      40:         {
      41:             Console.WriteLine("MyChannelListener<TChannel>.OnEndWaitForChannel()");
      42:             return this.InnerChannelListener.EndWaitForChannel(result);
      43:         } 
      44:  
      45:         protected override bool OnWaitForChannel(TimeSpan timeout)
      46:         {
      47:             Console.WriteLine("MyChannelListener<TChannel>.OnWaitForChannel()");
      48:             return this.InnerChannelListener.WaitForChannel(timeout);
      49:         } 
      50:  
      51:         public override Uri Uri
      52:         {
      53:             get 
      54:             {
      55:                 Console.WriteLine("MyChannelListener<TChannel>.Uri"); 
      56:                 return this.InnerChannelListener.Uri;
      57:             } 
      58:  
      59:         } 
      60:  
      61:         protected override void OnAbort()
      62:         {
      63:             Console.WriteLine("MyChannelListener<TChannel>.OnAbort()");
      64:             this.InnerChannelListener.Abort();
      65:         } 
      66:  
      67:         protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state)
      68:         {
      69:             Console.WriteLine("MyChannelListener<TChannel>.OnBeginClose()");
      70:             return this.InnerChannelListener.BeginClose(timeout, callback, state);
      71:         } 
      72:  
      73:         protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
      74:         {
      75:             Console.WriteLine("MyChannelListener<TChannel>.OnBeginOpen()");
      76:             return this.InnerChannelListener.BeginOpen(timeout, callback, state);
      77:         } 
      78:  
      79:         protected override void OnClose(TimeSpan timeout)
      80:         {
      81:             Console.WriteLine("MyChannelListener<TChannel>.OnClose()");
      82:             this.InnerChannelListener.Close(timeout);
      83:         } 
      84:  
      85:         protected override void OnEndClose(IAsyncResult result)
      86:         {
      87:             Console.WriteLine("MyChannelListener<TChannel>.OnEndClose()");
      88:             this.InnerChannelListener.EndClose(result);
      89:         } 
      90:  
      91:         protected override void OnEndOpen(IAsyncResult result)
      92:         {
      93:             Console.WriteLine("MyChannelListener<TChannel>.OnEndOpen()");
      94:             this.InnerChannelListener.EndOpen(result);
      95:         } 
      96:  
      97:         protected override void OnOpen(TimeSpan timeout)
      98:         {
      99:             Console.WriteLine("MyChannelListener<TChannel>.OnOpen()");
     100:             this.InnerChannelListener.Open(timeout);
     101:         }
     102:     }
     103: } 

    五、创建Custom Binding Element

    我们知道Binding是Service mode layer进入Channel layer的中介,而Binding由一系列的Binding element组成。我们上面创建的Channel factory和Channel listener需要最终通过对应的BindingElement应用到Binding中才能最终发挥作用。我们就来创建这个BindingElement:MyBindingElement。够简单吧,直接调用MyChannelFactory和MyChannelListener的构造函数就可以了。

       1: namespace Artech.ChannleStackExplore.Channels
       2: {
       3:   public class MyBindingElement:BindingElement
       4:     {
       5:         public override BindingElement Clone()
       6:         {
       7:             return new MyBindingElement();
       8:         } 
       9:  
      10:         public override T GetProperty<T>(BindingContext context)
      11:         {
      12:             return context.GetInnerProperty<T>();
      13:         } 
      14:  
      15:         public override IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingContext context)
      16:         {
      17:             Console.WriteLine("MyBindingElement.BuildChannelFactory()");
      18:             return new MyChannelFactory<TChannel>(context) as IChannelFactory<TChannel>;
      19:         } 
      20:  
      21:         public override IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContext context)
      22:         {
      23:             Console.WriteLine("MyBindingElement.BuildChannelListener()");
      24:             return new MyChannelListener<TChannel>(context) as IChannelListener<TChannel>;
      25:         }
      26:     }
      27: }

    六、创建Custom Binding

    我们进入了最后的阶段,创建一个Custom Binding。MyBinding继承Binding。 在CreateBindingElements方法中将我们的Binding element(MyBindingElement),连同其他必须的Binding element添加到BindingElementCollection 中。

       1: namespace Artech.ChannleStackExplore.Channels
       2: {
       3:     public class MyBinding:Binding
       4:     {
       5:         public override BindingElementCollection CreateBindingElements()
       6:         {
       7:             BindingElementCollection elemens = new BindingElementCollection();
       8:             elemens.Add(new TextMessageEncodingBindingElement());
       9:             elemens.Add(new MyBindingElement());
      10:             elemens.Add(new HttpTransportBindingElement());
      11:             return elemens.Clone();
      12:         } 
      13:  
      14:         public override string Scheme
      15:         {
      16:             get
      17:             {
      18:                 return "http";
      19:             }
      20:         }
      21:     }
      22: } 

    注:对BindElement的组装可以通过configuration来实现。

    七、使用Custom Binding

    我们上面所做的一切都汇集到我们的Custom binding:MyBinding。既然我们为之写了那么多代码,我们一定要通过某种方式测试一下它时候具有我们需要的功能。我们通过MyBinding创建一个Messaging via Binding的应用。不熟悉的朋友可以转到上一篇去熟悉一下。下面是Server端的代码。

       1: namespace Server
       2: {
       3:     class Program
       4:     {
       5:         static void Main(string[] args)
       6:         {
       7:             MyBinding binding = new MyBinding();
       8:             IChannelListener<IReplyChannel> channelListener= binding.BuildChannelListener<IReplyChannel>(new Uri("http://127.0.0.1:8888/messagingviabinding"));
       9:             channelListener.Open(); 
      10:  
      11:             while (true)
      12:             {
      13:                 IReplyChannel channel= channelListener.AcceptChannel(TimeSpan.MaxValue);
      14:                 channel.Open();
      15:                 RequestContext context = channel.ReceiveRequest(TimeSpan.MaxValue); 
      16:  
      17:                 Console.WriteLine("Receive a request message:\n{0}", context.RequestMessage);
      18:                 Message replyMessage = Message.CreateMessage(MessageVersion.Soap12WSAddressing10, "http://artech.messagingviabinding", "This is a mannualy created reply message for the purpose of testing");
      19:                 context.Reply(replyMessage);
      20:                 channel.Close();
      21:             }
      22:         }
      23:     }
      24: }
    下面是Client端的代码:  
       1: namespace Client
       2: {
       3:     class Program
       4:     {
       5:         static void Main(string[] args)
       6:         {
       7:             MyBinding binding = new MyBinding();
       8:             IChannelFactory<IRequestChannel> channelFactory = binding.BuildChannelFactory<IRequestChannel>();
       9:             channelFactory.Open(); 
      10:  
      11:             IRequestChannel channel = channelFactory.CreateChannel(new EndpointAddress("http://127.0.0.1:8888/messagingviabinding"));
      12:             channel.Open(); 
      13:  
      14:             Message requestMessage = Message.CreateMessage(MessageVersion.Soap12WSAddressing10, "http://artech.messagingviabinding", "This is a mannualy created reply message for the purpose of testing");
      15:             Message replyMessage = channel.Request(requestMessage);
      16:             Console.WriteLine("Receive a reply message:\n{0}", replyMessage);
      17:             channel.Close();
      18:             channelFactory.Close();
      19:             Console.Read();
      20:         } 
      21:  
      22:     }
      23: } 

    运行的结果将会是这样,下面是服务端输出结果:

    wcf2_02_01

    这是客户端的输出结果:

    wcf2_02_02

    通过上面的输出结果,你很直观的了解到了整个程序执行过程中,我们的定义在Channel,Channel factory,Channel listener和Binding element的方法是如何被依次执行的。 

    WCF后续之旅:
    WCF后续之旅(1): WCF是如何通过Binding进行通信的
    WCF后续之旅(2): 如何对Channel Layer进行扩展——创建自定义Channel
    WCF后续之旅(3): WCF Service Mode Layer 的中枢—Dispatcher
    WCF后续之旅(4):WCF Extension Point 概览
    WCF后续之旅(5): 通过WCF Extension实现Localization
    WCF后续之旅(6): 通过WCF Extension实现Context信息的传递
    WCF后续之旅(7):通过WCF Extension实现和Enterprise Library Unity Container的集成
    WCF后续之旅(8):通过WCF Extension 实现与MS Enterprise Library Policy Injection Application Block 的集成
    WCF后续之旅(9):通过WCF的双向通信实现Session管理[Part I]
    WCF后续之旅(9): 通过WCF双向通信实现Session管理[Part II]
    WCF后续之旅(10): 通过WCF Extension实现以对象池的方式创建Service Instance
    WCF后续之旅(11): 关于并发、回调的线程关联性(Thread Affinity)
    WCF后续之旅(12): 线程关联性(Thread Affinity)对WCF并发访问的影响
    WCF后续之旅(13): 创建一个简单的WCF SOAP Message拦截、转发工具[上篇]
    WCF后续之旅(13):创建一个简单的SOAP Message拦截、转发工具[下篇]
    WCF后续之旅(14):TCP端口共享
    WCF后续之旅(15): 逻辑地址和物理地址
    WCF后续之旅(16): 消息是如何分发到Endpoint的--消息筛选(Message Filter)
    WCF后续之旅(17):通过tcpTracer进行消息的路由

  • 相关阅读:
    lvm新增脚本
    k8s 开源web操作平台
    ES6 对象数组查找某一个对象
    Git常用命令使用大全
    Failed to read session data On PHP 7.2
    解决Apache无法解析PHP问题
    使用apache htpasswd生成加密的密码文件,并使用.htaccess控制目录访问
    Apache开启关闭错误提示
    linux查找目录下的所有文件中是否含有某个字符串
    抖音60秒视频权限开通方法
  • 原文地址:https://www.cnblogs.com/artech/p/1238626.html
Copyright © 2011-2022 走看看