当前位置: 首页 > news >正文

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: 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"
          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"
                  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: 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所示:

TerryLee_WCF_11  

图2

可以看到,服务正确的返回我们想要的消息,但是如果修改一下address为“http://localhost/anytao”,由于没有包含特定的字符“terrylee”,服务端将返回错误的信息:

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

输出结果如图3所示:

TerryLee_WCF_12

图3

结束语

本文我介绍了如何自定义消息筛选器,以及如何通过Behavior来修改EndpointDispatcher的默认过滤器,消息过滤是消息分发过程中非常重要的一个环节,也是WCF寻址中一个重要的部分,希望对于大家有所帮助。 WCF相关文章:

WCF专题系列(5):深入WCF寻址Part 5—逻辑地址和物理地址

WCF专题系列(3):深入WCF寻址Part 3—消息过滤引擎

WCF专题系列(2):深入WCF寻址Part 2—自定义寻址报头

WCF专题系列(1):深入WCF寻址Part 1—Web服务寻址规范

转载于:https://www.cnblogs.com/Terrylee/archive/2008/10/30/WCF-Addressing-Part3-Customize-Message-Filter.html

相关文章:

  • 拒绝只买现在,放弃未来,拒绝买工具型软件
  • Linux内核驱动模块
  • 千兆网线与百兆网线的区别
  • 远程安装oracle 10.2.1 for redhat 5.0 2.6.18-53.el5xen
  • 十二、EIGRP的手动汇总
  • C#委托事件
  • 自我管理
  • 隐藏私有文件
  • 关于iframe的name属性
  • T-SQL中的正则表达式
  • jsp中文件下载的实现
  • C# 多线程学习——定时器
  • iptables由概念到应用
  • 关闭 Windows Server 2008 用户权限控制(UAC)
  • 新来的 大家多关照下啊
  • “寒冬”下的金三银四跳槽季来了,帮你客观分析一下局面
  • 【Under-the-hood-ReactJS-Part0】React源码解读
  • CSS3 变换
  • JavaScript 基础知识 - 入门篇(一)
  • Java基本数据类型之Number
  • Laravel Telescope:优雅的应用调试工具
  • LintCode 31. partitionArray 数组划分
  • Vue ES6 Jade Scss Webpack Gulp
  • 初识 webpack
  • 记一次和乔布斯合作最难忘的经历
  • 腾讯优测优分享 | Android碎片化问题小结——关于闪光灯的那些事儿
  • ​iOS实时查看App运行日志
  • #AngularJS#$sce.trustAsResourceUrl
  • #stm32驱动外设模块总结w5500模块
  • (pojstep1.1.1)poj 1298(直叙式模拟)
  • (二)Linux——Linux常用指令
  • (二)七种元启发算法(DBO、LO、SWO、COA、LSO、KOA、GRO)求解无人机路径规划MATLAB
  • (分类)KNN算法- 参数调优
  • (附源码)SSM环卫人员管理平台 计算机毕设36412
  • (附源码)计算机毕业设计SSM在线影视购票系统
  • (黑客游戏)HackTheGame1.21 过关攻略
  • (每日持续更新)jdk api之StringBufferInputStream基础、应用、实战
  • (牛客腾讯思维编程题)编码编码分组打印下标题目分析
  • (四)Tiki-taka算法(TTA)求解无人机三维路径规划研究(MATLAB)
  • (续)使用Django搭建一个完整的项目(Centos7+Nginx)
  • (一)【Jmeter】JDK及Jmeter的安装部署及简单配置
  • (一)Neo4j下载安装以及初次使用
  • (转)es进行聚合操作时提示Fielddata is disabled on text fields by default
  • *setTimeout实现text输入在用户停顿时才调用事件!*
  • .CSS-hover 的解释
  • .NET Framework杂记
  • .Net 高效开发之不可错过的实用工具
  • .NET/C# 在 64 位进程中读取 32 位进程重定向后的注册表
  • .net遍历html中全部的中文,ASP.NET中遍历页面的所有button控件
  • .NET企业级应用架构设计系列之技术选型
  • .NET设计模式(2):单件模式(Singleton Pattern)
  • .NET微信公众号开发-2.0创建自定义菜单
  • @Valid和@NotNull字段校验使用
  • @四年级家长,这条香港优才计划+华侨生联考捷径,一定要看!
  • [3D基础]理解计算机3D图形学中的坐标系变换