程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> WCF後續之旅(2) 如何對Channel Layer進行擴展——創建自定義Channel

WCF後續之旅(2) 如何對Channel Layer進行擴展——創建自定義Channel

編輯:關於.NET

在上一篇文章中,我們通過一個直接借助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

public interface 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方法(同步/異步):

public interface 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方法(同步/異步):上面。

public interface 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的定義上就可以看出來:

public interface 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
{
  public class MyRequestChannel :ChannelBase, IRequestChannel
  {
    private IRequestChannel InnerChannel
    {get;set;}

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

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

    protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state)
    {
      Console.WriteLine("MyRequestChannel.OnBeginClose()");
      return this.InnerChannel.BeginClose(timeout, callback, state);
    }

    protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
    {
      Console.WriteLine("MyRequestChannel.OnBeginOpen()");
      return this.InnerChannel.BeginOpen(timeout, callback, state);
    }

    protected override void OnClose(TimeSpan timeout)
    {
      Console.WriteLine("MyRequestChannel.OnClose()");
      this.Close(timeout);
    }

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

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

    protected override void 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()");
      return this.BeginRequest(message, timeout, callback, state);
    }

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

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

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

    }

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

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

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

    }

    #endregion
  }
}

這裡唯一需要注意的一點是:在實際的運行環境中,我們的channel僅僅了位於Channel stack的某個環節。該channel和其他的一些channel組成一個管道,這個管道裡流淌是Message。所以當一個Channel執行了它相應的操作的時候,需要將message傳到下一個channel作進一步處理。所有我們的Channel需要下一個Channel的應用,這個Channel就是我們的InnerChannel字段,該成員在構造函數中指定。

private IRequestChannel InnerChannel
{get;set;}

public MyRequestChannel(ChannelManagerBase channleManager, IRequestChannel innerChannel)
      : base(channleManager)
{
  this.InnerChannel = innerChannel;
}
所以,對於每一個方法,在實現了本Channel的功能之後,只需要調用InnerChannel 的對應的方法即可。

我們再來看看實現了IReplyChannel的MyReplyChannel, 它用於接收方:

namespace Artech.ChannleStackExplore.Channels
{
  public class MyReplyChannel: ChannelBase, IReplyChannel
  {
    private IReplyChannel InnerChannel
    { get; set; }

    public MyReplyChannel(ChannelManagerBase channelManager, IReplyChannel innerChannel):base(channelManager)
    {
      this.InnerChannel = innerChannel;
    }

    ChannelBase Members#region ChannelBase Members
    protected override void OnAbort()
    {
      Console.WriteLine("MyReplyChannel.OnAbort()");
      this.InnerChannel.Abort();
    }

    protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state)
    {
      Console.WriteLine("MyReplyChannel.OnBeginClose()");
      return this.InnerChannel.BeginClose(timeout, callback, state);
    }

    protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
    {
      Console.WriteLine("MyReplyChannel.OnBeginOpen()");
      return this.InnerChannel.BeginOpen(timeout, callback, state);
    }

    protected override void OnClose(TimeSpan timeout)
    {
      Console.WriteLine("MyReplyChannel.OnClose()");
      this.Close(timeout);
    }

    protected override void OnEndClose(IAsyncResult result)
    {
      Console.WriteLine("MyReplyChannel.OnEndClose()");
      this.InnerChannel.EndClose(result);
    }

    protected override void OnEndOpen(IAsyncResult result)
    {
      Console.WriteLine("MyReplyChannel.OnEndOpen()");
      this.InnerChannel.EndOpen(result);
    }

    protected override void OnOpen(TimeSpan timeout)
    {
      Console.WriteLine("MyReplyChannel.OnOpen()");
      this.InnerChannel.Open(timeout);
    }
    #endregion

    IReplyChannel Members#region IReplyChannel Members

    public IAsyncResult BeginReceiveRequest(TimeSpan timeout, AsyncCallback callback, object state)
    {
      Console.WriteLine("MyReplyChannel.BeginReceiveRequest()");
      return this.InnerChannel.BeginReceiveRequest(timeout, callback, state);
    }

    public IAsyncResult BeginReceiveRequest(AsyncCallback callback, object state)
    {
      Console.WriteLine("MyReplyChannel.BeginReceiveRequest()");
      return this.InnerChannel.BeginReceiveRequest(callback, state);
    }

    public IAsyncResult BeginTryReceiveRequest(TimeSpan timeout, AsyncCallback callback, object state)
    {
      Console.WriteLine("MyReplyChannel.BeginTryReceiveRequest()");
      return this.InnerChannel.BeginTryReceiveRequest(timeout, callback, state);
    }

    public IAsyncResult BeginWaitForRequest(TimeSpan timeout, AsyncCallback callback, object state)
    {
      Console.WriteLine("MyReplyChannel.BeginWaitForRequest()");
      return this.InnerChannel.BeginWaitForRequest(timeout, callback, state);
    }

    public RequestContext EndReceiveRequest(IAsyncResult result)
    {
      Console.WriteLine("MyReplyChannel.EndReceiveRequest()");
      return this.InnerChannel.EndReceiveRequest(result);
    }

    public bool EndTryReceiveRequest(IAsyncResult result, out RequestContext context)
    {
      Console.WriteLine("MyReplyChannel.EndTryReceiveRequest()");
      return this.InnerChannel.EndTryReceiveRequest(result, out context);
    }

    public bool EndWaitForRequest(IAsyncResult result)
    {
      Console.WriteLine("MyReplyChannel.EndWaitForRequest()");
      return this.InnerChannel.EndWaitForRequest(result);
    }

    public System.ServiceModel.EndpointAddress LocalAddress
    {
      get
      {
        Console.WriteLine("MyReplyChannel.LocalAddress");
        return this.InnerChannel.LocalAddress;
      }
    }

    public RequestContext ReceiveRequest(TimeSpan timeout)
    {
      Console.WriteLine("MyReplyChannel.ReceiveRequest()");
      return this.InnerChannel.ReceiveRequest(timeout);
    }

    public RequestContext ReceiveRequest()
    {
      Console.WriteLine("MyReplyChannel.ReceiveRequest()");
      return this.InnerChannel.ReceiveRequest();
    }

    public bool TryReceiveRequest(TimeSpan timeout, out RequestContext context)
    {
      Console.WriteLine("MyReplyChannel.TryReceiveRequest()");
      return this.InnerChannel.TryReceiveRequest(timeout, out context);
    }

    public bool WaitForRequest(TimeSpan timeout)
    {
      Console.WriteLine("MyReplyChannel.WaitForRequest()");
      return this.InnerChannel.WaitForRequest(timeout);
    }

    #endregion
  }
}

MyReplyChannel的定義方式和MyRequestChannel完全一樣,我們就不用再多說什麼了。

4. 創建Custom Channel Factory & Channel Listener

通過上一篇文章的介紹,我們知道Channel是通過Channel Manager來創建並管理的,在發送方的Channel Manager被稱為Channel Factory。

對於Channel factory,除了定義了兩個Interface之外(IChannelFactory 和IChannelFactory<TChannel>)

public interface IChannelFactory : ICommunicationObject
  {
    // Methods
    T GetProperty<T>() where T : class;
  }

public interface IChannelFactory<TChannel> : IChannelFactory, ICommunicationObject
{
  // Methods
  TChannel CreateChannel(EndpointAddress to);
  TChannel CreateChannel(EndpointAddress to, Uri via);
}

還定義了兩個Base class:ChannelFactoryBase 和ChannelFactoryBase<TChannel>(限於篇幅,在這裡就不多作介紹了)。

為了簡單起見,我們上我們的Channel factory繼承自ChannelFactoryBase<TChannel>:

namespace Artech.ChannleStackExplore.Channels
{
  public class MyChannelFactory<TChannel> : ChannelFactoryBase<TChannel>
  {
    private IChannelFactory<TChannel> InnerChannelFactory
    { get; set; }

    public MyChannelFactory(BindingContext context)
    {
      this.InnerChannelFactory = context.BuildInnerChannelFactory<TChannel>();
    }

    protected override TChannel OnCreateChannel(EndpointAddress address, Uri via)
    {
      Console.WriteLine("MyChannelFactory<TChannel>.OnClose()");
      TChannel innerChannel = this.InnerChannelFactory.CreateChannel(address, via);
      return (TChannel)(object)(new MyRequestChannel(this, innerChannel as IRequestChannel));
    }

    protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
    {
      Console.WriteLine("MyChannelFactory<TChannel>.OnBeginOpen()");
      return this.InnerChannelFactory.BeginOpen(timeout, callback, state);
    }

    protected override void OnEndOpen(IAsyncResult result)
    {
      Console.WriteLine("MyChannelFactory<TChannel>.OnEndOpen()");
      this.InnerChannelFactory.EndOpen(result);
    }

    protected override void OnOpen(TimeSpan timeout)
    {
      Console.WriteLine("MyChannelFactory<TChannel>.OnOpen()");
      this.InnerChannelFactory.Open();
    }
  }
}

我們說過,和Channel stack一樣,Channel factory仍然是一個stack,原因很簡單,一個個的Channel需要相應的channel factory來創建。同Channel一樣,當channel factory創建了自己的channel之後需要將接力棒交到下一個Channel factory。不過不通於Channel的是,下一個Channel factory不時在構造函數直接指定的,而是通過構造函數中的BindingContext 對象的BuildInnerChannelFactory()創建。

private IChannelFactory<TChannel> InnerChannelFactory
{ get; set; }

public MyChannelFactory(BindingContext context)
{
   this.InnerChannelFactory = context.BuildInnerChannelFactory<TChannel>();
}

注:BindingContext 的兩個最重要的方法就是BuildInnerChannelFactory和BuildInnerChannelListener。前者創建Inner channel factory後者創建Inner Channel listener。

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

namespace Artech.ChannleStackExplore.Channels
{
  public class MyChannelListener<TChannel> : ChannelListenerBase<TChannel> where TChannel : class, IChannel
  {
    private IChannelListener<TChannel> InnerChannelListener
    { get; set; }

    public MyChannelListener(BindingContext context)
    {
      this.InnerChannelListener = context.BuildInnerChannelListener<TChannel>();
    }

    protected override TChannel OnAcceptChannel(TimeSpan timeout)
    {
      Console.WriteLine("MyChannelListener<TChannel>.OnAcceptChannel()");
      TChannel innerChannel = this.InnerChannelListener.AcceptChannel(timeout);
      return new MyReplyChannel(this, innerChannel as IReplyChannel) as TChannel;
    }

    protected override IAsyncResult OnBeginAcceptChannel(TimeSpan timeout, AsyncCallback callback, object state)
    {
      Console.WriteLine("MyChannelListener<TChannel>.OnBeginAcceptChannel()");
      return this.InnerChannelListener.BeginAcceptChannel(timeout, callback, state);
    }

    protected override TChannel OnEndAcceptChannel(IAsyncResult result)
    {
      Console.WriteLine("MyChannelListener<TChannel>.OnEndAcceptChannel()");
      TChannel innerChannel = this.InnerChannelListener.EndAcceptChannel(result);
      return new MyReplyChannel(this, innerChannel as IReplyChannel) as TChannel;
    }

    protected override IAsyncResult OnBeginWaitForChannel(TimeSpan timeout, AsyncCallback callback, object state)
    {
      Console.WriteLine("MyChannelListener<TChannel>.OnBeginWaitForChannel()");
      return this.InnerChannelListener.BeginWaitForChannel(timeout, callback, state);
    }

    protected override bool OnEndWaitForChannel(IAsyncResult result)
    {
      Console.WriteLine("MyChannelListener<TChannel>.OnEndWaitForChannel()");
      return this.InnerChannelListener.EndWaitForChannel(result);
    }

    protected override bool OnWaitForChannel(TimeSpan timeout)
    {
      Console.WriteLine("MyChannelListener<TChannel>.OnWaitForChannel()");
      return this.InnerChannelListener.WaitForChannel(timeout);
    }

    public override Uri Uri
    {
      get
      {
        Console.WriteLine("MyChannelListener<TChannel>.Uri");
        return this.InnerChannelListener.Uri;
      }

    }

    protected override void OnAbort()
    {
      Console.WriteLine("MyChannelListener<TChannel>.OnAbort()");
      this.InnerChannelListener.Abort();
    }

    protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state)
    {
      Console.WriteLine("MyChannelListener<TChannel>.OnBeginClose()");
      return this.InnerChannelListener.BeginClose(timeout, callback, state);
    }

    protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
    {
      Console.WriteLine("MyChannelListener<TChannel>.OnBeginOpen()");
      return this.InnerChannelListener.BeginOpen(timeout, callback, state);
    }

    protected override void OnClose(TimeSpan timeout)
    {
      Console.WriteLine("MyChannelListener<TChannel>.OnClose()");
      this.InnerChannelListener.Close(timeout);
    }

    protected override void OnEndClose(IAsyncResult result)
    {
      Console.WriteLine("MyChannelListener<TChannel>.OnEndClose()");
      this.InnerChannelListener.EndClose(result);
    }

    protected override void OnEndOpen(IAsyncResult result)
    {
      Console.WriteLine("MyChannelListener<TChannel>.OnEndOpen()");
      this.InnerChannelListener.EndOpen(result);
    }

    protected override void OnOpen(TimeSpan timeout)
    {
      Console.WriteLine("MyChannelListener<TChannel>.OnOpen()");
      this.InnerChannelListener.Open(timeout);
    }
  }
}

5. 創建Custom Binding Element

我們知道Binding是Service mode layer進入Channel layer的中介,而Binding由一系列的Binding element組成。我們上面創建的Channel factory和Channel listener需要最終通過對應的BindingElement應用到Binding中才能最終發揮作用。我們就來創建這個BindingElement:MyBindingElement。

namespace Artech.ChannleStackExplore.Channels
{
 public class MyBindingElement:BindingElement
  {
    public override BindingElement Clone()
    {
      return new MyBindingElement();
    }

    public override T GetProperty<T>(BindingContext context)
    {
      return context.GetInnerProperty<T>();
    }

    public override IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingContext context)
    {
      Console.WriteLine("MyBindingElement.BuildChannelFactory()");
      return new MyChannelFactory<TChannel>(context) as IChannelFactory<TChannel>;
    }

    public override IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContext context)
    {
      Console.WriteLine("MyBindingElement.BuildChannelListener()");
      return new MyChannelListener<TChannel>(context) as IChannelListener<TChannel>;
    }
  }
}

夠簡單吧,直接調用MyChannelFactory和MyChannelListener的構造函數就可以了。

6. 創建Custom Binding

我們進入了最後的階段,創建一個Custom Binding。MyBinding繼承Binding class。 在CreateBindingElements方法中將我們的Binding element(MyBindingElement),連同其他必須的Binding element添加到BindingElementCollection 中。

namespace Artech.ChannleStackExplore.Channels
{
  public class MyBinding:Binding
  {
    public override BindingElementCollection CreateBindingElements()
    {
      BindingElementCollection elemens = new BindingElementCollection();
      elemens.Add(new TextMessageEncodingBindingElement());
      elemens.Add(new MyBindingElement());
      elemens.Add(new HttpTransportBindingElement());
      return elemens.Clone();
    }

    public override string Scheme
    {
      get
      {
        return "http";
      }
    }
  }
}

注:對BindElement的組裝可以通過configuration來實現。

7. 使用Custom Binding

我們上面所做的一切都匯集到我們的Custom binding:MyBinding。既然我們為之寫了那麼多代碼,我們一定要通過某種方式測試一下它時候具有我們需要的功能。我們通過MyBinding創建一個Messaging via Binding的應用。不熟悉的朋友可以轉到上一篇去熟悉一下。

Server端的代碼:

namespace Server
{
  class Program
  {
    static void Main(string[] args)
    {
      MyBinding binding = new MyBinding();
      IChannelListener<IReplyChannel> channelListener= binding.BuildChannelListener<IReplyChannel>(new Uri("http://127.0.0.1:8888/messagingviabinding"));
       channelListener.Open();

      while (true)
      {
        IReplyChannel channel= channelListener.AcceptChannel(TimeSpan.MaxValue);
        channel.Open();
        RequestContext context = channel.ReceiveRequest(TimeSpan.MaxValue);

        Console.WriteLine("Receive a request message:\n{0}", context.RequestMessage);
        Message replyMessage = Message.CreateMessage(MessageVersion.Soap12WSAddressing10, "http://artech.messagingviabinding", "This is a mannualy created reply message for the purpose of testing");
         context.Reply(replyMessage);
        channel.Close();
      }
    }
  }
}

Client端的代碼:

namespace Client
{
  class Program
  {
    static void Main(string[] args)
    {
      MyBinding binding = new MyBinding();
      IChannelFactory<IRequestChannel> channelFactory = binding.BuildChannelFactory<IRequestChannel>();
      channelFactory.Open();

      IRequestChannel channel = channelFactory.CreateChannel(new EndpointAddress("http://127.0.0.1:8888/messagingviabinding"));
       channel.Open();

      Message requestMessage = Message.CreateMessage(MessageVersion.Soap12WSAddressing10, "http://artech.messagingviabinding", "This is a mannualy created reply message for the purpose of testing");
       Message replyMessage = channel.Request(requestMessage);
      Console.WriteLine("Receive a reply message:\n{0}", replyMessage);
      channel.Close();
      channelFactory.Close();
      Console.Read();
    }

  }
}

運行的結果將會是這樣:

Server:

Client:

通過上面的輸出結果,你很直觀的了解到了整個程序執行過程中,我們的定義在Channel,Channel factory,Channel listener和Binding element的方法是如何被依次執行的。

本文配套源碼

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved