WCF後傳系列(4):深刻WCF尋址Part 4—自定義消息篩選器

概述

WCF專題系列(3):深刻WCF尋址Part 3—消息過濾引擎一文中,詳細介紹了WCF中的消息篩選引擎,包括消息篩選器和篩選器表,每一個EndpointDispatcher都包含了兩個消息篩選器,默認的地址過濾器是EndpointAddressMessageFilter,默認的契約過濾器是ActionMessageFilter,這些是能夠經過Behavior來改變的。本文咱們將學習如何建立一個自定義的消息過濾器,並經過自定義Behavior來改變EndpointDispatcher的默認過濾器。

自定義過濾器

在默認狀況下,默認狀況下,僅當消息的「To」標頭爲終結點的 EndpointAddress 而且消息的動做與終結點操做的動做之一匹配時,終結點的消息篩選器才與此消息匹配。在本文中,咱們將自定義一個消息過濾器,它不要求消息的「To」標頭徹底與EndpointAddress徹底匹配,而只是檢測SOAP消息中的「To」標頭中是否包含某些特定的字符。全部的消息過濾器都從MessageFilter基類繼承,以下代碼所示:
/// <summary>
/// Author: TerryLee
/// Url: [url]http://www.cnblogs.com/terrylee[/url]
/// </summary>
public class SpecialCharactersMessageFilter : MessageFilter
{
    private String _characters = String.Empty;
    public SpecialCharactersMessageFilter(string characters)
    {
        this._characters = characters;
    }
    public override bool Match(Message message)
    {
        Uri to = message.Headers.To;
        if (to == null)
            return false;
        return to.AbsoluteUri.Contains(_characters);
    }
    public override bool Match(MessageBuffer buffer)
    {
        return Match(buffer.CreateMessage());
    }
}
SpecialCharactersMessageFilter的實現很是簡單,僅僅是查找「To」標頭是否包含某些特定字符,這些字符咱們會在配置文件中進行配置。

定義EndpointBehavior

如今咱們自定義一個EndpointBehavior,使用它來替換EndpointDispatcher上的地址過濾器和契約過濾器,它實現自IendpointBehavior接口,以下代碼所示:
/// <summary>
/// Author: TerryLee
/// Url: [url]http://www.cnblogs.com/terrylee[/url]
/// </summary>
public class FilteringEndpointBehavior : IEndpointBehavior
{
    MessageFilter addressFilter;
    MessageFilter contractFilter;
    public FilteringEndpointBehavior(MessageFilter addressFilter, 
        MessageFilter contractFilter)
    {
        this.addressFilter = addressFilter;
        this.contractFilter = contractFilter;
    }
    public void AddBindingParameters(ServiceEndpoint endpoint, 
        BindingParameterCollection bindingParameters)
    {
        
    }
    public void ApplyClientBehavior(ServiceEndpoint endpoint, 
        ClientRuntime clientRuntime)
    {
        throw new InvalidOperationException(
            "This behavior should only be used on the server.");
    }
    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, 
        EndpointDispatcher endpointDispatcher)
    {
        endpointDispatcher.AddressFilter = this.addressFilter;
        endpointDispatcher.ContractFilter = this.contractFilter;
    }
    public void Validate(ServiceEndpoint endpoint)
    {
        
    }
}
這裏只是實現了ApplyDispatchBehavior方法,其它方法暫時先不用考慮,另外,因爲該Behavior只是用在服務端,因此在ApplyClientBehavior方法中拋出一個異常。

定義行爲擴展

接下來定義一個行爲擴展元素,這裏定義了一個Characters的屬性,用來在配置文件中指定消息過濾器中用到的特殊字符,以下代碼所示:
/// <summary>
/// Author: TerryLee
/// Url: [url]http://www.cnblogs.com/terrylee[/url]
/// </summary>
public class FilteringEndpointBehaviorExtension
    : BehaviorExtensionElement
{
    protected override object CreateBehavior()
    {
        MessageFilter addressFilter = 
            new SpecialCharactersMessageFilter(Characters);
        MessageFilter contractFilter = 
            new MatchAllMessageFilter();
        return new FilteringEndpointBehavior(addressFilter, contractFilter);
    }
    public override Type BehaviorType
    {
        get 
        { 
            return typeof(FilteringEndpointBehavior);
        }
    }
    [ConfigurationProperty("characters", 
        DefaultValue = "terrylee", IsRequired = true)]
    public String Characters
    {
        get {
            return base["characters"].ToString(); 
        }
        set { 
            base["characters"] = value; 
        }
    }
}

配置服務

定義一個簡單的服務契約以及服務的實現,代碼以下,再也不多說:
/// <summary>
/// Author: TerryLee
/// Url: [url]http://www.cnblogs.com/terrylee[/url]
/// </summary>
[ServiceContract(Namespace = "http://www.cnblogs.com/terrylee/")]
public interface IEchoService
{
    [OperationContract]
    string Echo(string msg);
}
public class EchoService : IEchoService
{
    public string Echo(string msg)
    {
        return "Hello:" + msg;
    }
}
如今來看一下服務端的配置,除了必須的終結點配置以外,爲服務註冊一個新的Behavior,代碼以下所示:
<extensions>
  <behaviorExtensions>
    <add name="filteringEndpointBehavior" 
         type="TerryLee.CustomizeMessageFilter.Service.
         FilteringEndpointBehaviorExtension, Service, 
         Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
  </behaviorExtensions>
</extensions>
建立EndpointBehavior配置:
<endpointBehaviors>
  <behavior name="filterBehavior">
    <filteringEndpointBehavior characters="terrylee" />
  </behavior>
</endpointBehaviors>
服務終結點使用behaviorConfiguration:
<endpoint address=""
          binding ="wsHttpBinding"
          contract="TerryLee.CustomizeMessageFilter.Service.IEchoService"
          behaviorConfiguration="filterBehavior">
</endpoint>
最終完整的配置文件:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <services>
      <service name="TerryLee.CustomizeMessageFilter.Service.EchoService"
               behaviorConfiguration="echoBehavior">
        <host>
          <baseAddresses>
            <add baseAddress="[url]http://localhost:8887/EchoService[/url]"/>
          </baseAddresses>
        </host>
        <endpoint address=""
                  binding ="wsHttpBinding"
                  contract="TerryLee.CustomizeMessageFilter.Service.IEchoService"
                  behaviorConfiguration="filterBehavior">
        </endpoint>
      </service>
    </services>
    <extensions>
      <behaviorExtensions>
        <add name="filteringEndpointBehavior" 
             type="TerryLee.CustomizeMessageFilter.Service.
             FilteringEndpointBehaviorExtension, Service, 
             Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
      </behaviorExtensions>
    </extensions>
  <behaviors>
    <serviceBehaviors>
      <behavior name="echoBehavior">
        <serviceMetadata httpGetEnabled="true"/>
      </behavior>
    </serviceBehaviors>
    <endpointBehaviors>
      <behavior name="filterBehavior">
        <filteringEndpointBehavior characters="terrylee" />
      </behavior>
    </endpointBehaviors>
  </behaviors>
  </system.serviceModel>
</configuration>
至此服務端配置完成,根據配置,只有SOAP消息「To」標頭中包含有「terrylee」的字符時,此時終結點的消息過濾器才與此消息匹配。如今在控制檯中輸出一下,看看針對配置的終結點它所使用的地址過濾器和契約過濾器分別是什麼,如圖1所示:
TerryLee_WCF_10
圖1
能夠看到,終結點所用的地址過濾器再也不是默認的EndpointAddressMessageFilter,而是咱們自定義的SpecialCharactersMessageFilter。

客戶端測試

經過上面的配置,咱們知道,只有SOAP消息的「To」標頭中帶有「terrylee」字符,消息纔會被分發到相應的終結點上。如今編寫一個簡單的測試客戶端程序,以下代碼所示:
/// <summary>
/// Author: TerryLee
/// Url: [url]http://www.cnblogs.com/terrylee[/url]
/// </summary>
static void Main()
{
    Uri serviceVia = new Uri("http://localhost:8887/EchoService");
    WSHttpBinding binding = new WSHttpBinding();
    ChannelFactory<IEchoService> factory = new ChannelFactory<IEchoService>
        (binding, new EndpointAddress(serviceVia));
    String address = "http://localhost/terrylee";
    Console.WriteLine(String.Format("Sending message to {0}...", address));
    IEchoService channel = factory.CreateChannel(
        new EndpointAddress(address), serviceVia);
    try
    {
        String reply = channel.Echo("cnblogs");
        Console.WriteLine(reply.ToString());
        ((IClientChannel)channel).Close();
    }
    catch (CommunicationException ce)
    {
        Console.WriteLine("Exception: {0}", ce.Message);
        ((IClientChannel)channel).Abort();
    }
    Console.WriteLine("Press <ENTER> to terminate client.");
    Console.ReadLine();
}
因爲定義了終結點的邏輯地址爲「[url]http://localhost/terrylee[/url]」,符合咱們上面所講的條件,能夠看到輸出結果如圖2所示:
TerryLee_WCF_11  
圖2
能夠看到,服務正確的返回咱們想要的消息,可是若是修改一下address爲「[url]http://localhost/anytao[/url]」,因爲沒有包含特定的字符「terrylee」,服務端將返回錯誤的信息:
String address = "[url]http://localhost/anytao[/url]";
輸出結果如圖3所示:
TerryLee_WCF_12
圖3

結束語

本文我介紹瞭如何自定義消息篩選器,以及如何經過Behavior來修改EndpointDispatcher的默認過濾器,消息過濾是消息分發過程當中很是重要的一個環節,也是WCF尋址中一個重要的部分,但願對於你們有所幫助。 WCF相關文章:

0javascript

收藏css

lihuijun

203篇文章,74W+人氣,0粉絲

Ctrl+Enter 發佈html

發佈java

取消python

掃一掃,領取大禮包mysql

0jquery

分享
lihuijun
相關文章
相關標籤/搜索