程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> WCF專題系列(4):深入WCF尋址Part 4—自定義消息篩選器

WCF專題系列(4):深入WCF尋址Part 4—自定義消息篩選器

編輯:關於.NET

概述

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

自定義過濾器

在默認情況下,默認情況下,僅當消息的 “To”標頭為終結點的 EndpointAddress 並且消息的動作與終結點 操作的動作之一匹配時,終結點的消息篩選器才與此消息匹配。在本文中,我們 將自定義一個消息過濾器,它不要求消息的“To”標頭完全與 EndpointAddress完全匹配,而只是檢測SOAP消息中的“To”標頭中 是否包含某些特定的字符。所有的消息過濾器都從MessageFilter基類繼承,如 下代碼所示:

/// <summary>
/// Author: TerryLee
/// Url: http://www.cnblogs.com/terrylee
/// </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: http://www.cnblogs.com/terrylee
/// </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: http://www.cnblogs.com/terrylee
/// </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: http://www.cnblogs.com/terrylee
/// </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&qu ot;
      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="http://localhost:8887/EchoService"/>
      </baseAddresses>
    </host>
     <endpoint address=""
         binding ="wsHttpBinding"
          contract="TerryLee.CustomizeMessageFilter.Service.IEchoService&qu ot;
          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所示:

圖1

可以看到,終結點所用的地址過濾器不再是默認的 EndpointAddressMessageFilter,而是我們自定義的 SpecialCharactersMessageFilter。

客戶端測試

通過上面的配置,我 們知道,只有SOAP消息的“To”標頭中帶有“terrylee” 字符,消息才會被分發到相應的終結點上。現在編寫一個簡單的測試客戶端程序 ,如下代碼所示:

/// <summary>
/// Author: TerryLee
/// Url: http://www.cnblogs.com/terrylee
/// </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();
}

由於定義了終結點的邏輯地址為 “http://localhost/terrylee”,符合我們上面所講的條件,可以 看到輸出結果如圖2所示:

 

圖2

可以看到,服務正確的返回我們想要的消息,但是如果修改 一下address為“http://localhost/anytao”,由於沒有包含特定的 字符“terrylee”,服務端將返回錯誤的信息:

String address = "http://localhost/anytao";

輸出結果如圖3所示:

圖3

結束語本文我介紹了如何自定義消息篩選器,以及如何通 過Behavior來修改EndpointDispatcher的默認過濾器,消息過濾是消息分發過程 中非常重要的一個環節,也是WCF尋址中一個重要的部分,希望對於大家有所幫 助。

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