概述

通过前面两篇的介绍,对Web服务寻址规范以及在WCF开发中终结点地址有了深入的认识。本文我们继续深入WCF寻址第三部分内容,当消息传入时,如何来确定匹配的终结点,就是我们本文要讲到的消息筛选引擎。在WCF中,消息筛选器引擎包括两个重要的组成部分:筛选器和筛选器表。

认识消息筛选器

在WCF中当有消息传入时,它使用消息筛选器来确定匹配的终结点,每个终结点实际上关联着两个筛选器:一个地址筛选器和一个契约筛选器。地址筛选器确定传入消息是否匹配终结点的“To”地址和任何必需的地址报头,而契约筛选器则确定它是否匹配终结点的契约,两个筛选器都被调度程序用来确定目标终结点。

在WCF中,所有的消息筛选器都继承于MessageFilter抽象基类,系统内置了几种的消息筛选器,如图1所示:

图1

EndpointAddressMessageFilter:作为默认的地址筛选器,它会将SOAP消息中的“To”地址与终结点地址进行比较,预期它们完全匹配,也会传入消息中获得的寻址报头和终结点要求的一组寻址报头进行比较,要使最终匹配的结果返回true,必须满足以下两个条件:

1. 筛选器的地址统一资源标识符 (URI) 必须与消息 To 标头中的统一资源标识符相同。

2. 筛选器地址中的每个终结点参数都必须在消息中找到一个与之匹配的标头。

ActionMessageFilter:作为默认的契约筛选器,它根据传入的SAOP消息中“Action”值和契约上的操作进行比较,确定是否匹配匹配。该筛选器在初始化时将包含一个操作字符串列表,如果筛选器的列表中的任一操作与消息或消息缓冲区中的 Action 标头匹配,则 Match 方法返回 true。 如果该列表为空,则将该筛选器视为全匹配型筛选器,任何消息或消息缓冲区都与该筛选器匹配,并且 Match 返回 true。 如果筛选器列表中没有任何操作与消息或消息缓冲区中的 Action 标头匹配,则 Match 返回 false。 如果消息中不存在任何操作且筛选器的列表非空,则 Match 返回 false。

PrefixEndpointAddressMessageFilter:此筛选器与 EndpointAddressMessageFilter 执行相同的查询,不同的是测试消息是否与终结点地址相匹配是由“最长前缀匹配”完成的。这表示筛选器中指定的 URI 不需要与消息的 URI 完全匹配,不过必须作为前缀包含在该 URI 中。例如,如果筛选器指定地址“[url]http://www.foo.com[/url]”,并且消息是发送给“[url]http://www.foo.com/customerA[/url]”,则将满足筛选器查询条件的 URI 部分,但是筛选器查询的报头部分仍需要完成。

MatchAllMessageFilter:该筛选器将导致所有消息都匹配给定终结点,看一下它的Match方法实现,除非消息为空,否则就返回True:

[DataContract]
public class MatchAllMessageFilter : MessageFilter
{public override bool Match(Message message){if (message == null){throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("message");}return true;}
}
MatchNoneMessageFilter:该筛选器将导致所有消息都不匹配,看一下它的Match方法实现,除非消息为空,否则就返回False:

[DataContract]
public class MatchNoneMessageFilter : MessageFilter
{public override bool Match(Message message){if (message == null){throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("message");}return false;}
}
XpathMessageFilter:使用 XPath 1.0 表达式来指定匹配的条件。

除此之外,我们可以自定义自己的消息筛选器,在本系列的后面将会讲到。

筛选器工作原理

正如在前面所看到的,MessageFilter提供了所有筛选器的基类,筛选器中的Match方法用于确定消息是否满足筛选器的条件。如下面的代码片段中,我们定义两个ActionMessageFilter和EndpointAddressMessageFilter,然后创建一个Message,看看它们最终匹配的结果:

static void Main(string[] args)
{// 创建两个ActionMessageFilter实例ActionMessageFilter actionFilter1 = new ActionMessageFilter("Add", "Sub");ActionMessageFilter actionFilter2 = new ActionMessageFilter("Mul");// 创建两个EndpointAddressMessageFilter实例EndpointAddressMessageFilter addressFilter1 = new EndpointAddressMessageFilter(new EndpointAddress("http://localhost:8887/Calculator"));EndpointAddressMessageFilter addressFilter2 = new EndpointAddressMessageFilter(new EndpointAddress("http://www.cnblogs.com/terrylee"));// 创建一个Message,设置Action和ToMessage message = Message.CreateMessage(MessageVersion.Soap12WSAddressing10,"myBody");message.Headers.Action = "Add";message.Headers.To = new Uri("http://localhost:8887/Calculator");// 测试匹配结果bool actionResult1 = actionFilter1.Match(message);bool actionResult2 = actionFilter2.Match(message);bool addressResult1 = addressFilter1.Match(message);bool addressResult2 = addressFilter2.Match(message);// 输出结果Console.WriteLine("The result of filter:");Console.WriteLine(actionResult1);Console.WriteLine(actionResult2);Console.WriteLine(addressResult1);Console.WriteLine(addressResult2);Console.ReadLine();
}
输出结果如图2所示:

图2

在该示例中,由于我们创建的Message对象,最终的SOAP消息包如下代码所示:

<s:Envelope xmlns:s="[url]http://www.w3.org/2003/05/soap-envelope[/url]"xmlns:a="[url]http://www.w3.org/2005/08/addressing[/url]"><s:Header><a:To s:mustUnderstand="1">[url]http://localhost:8887/Calculator[/url]</a:To><a:Action s:mustUnderstand="1">Add</a:Action></s:Header><s:Body></s:Body>
</s:Envelope>
所以这里匹配上的是actionFilter1和addressFilter1。注意,一旦构造筛选器,筛选器使用的条件无法更改,因为筛选器表无法检测更改。修改筛选器的条件的唯一方法是构造一个新的筛选器,然后删除现有筛选器。

消息筛选器表

消息筛选器表用于存储键-值对,其中筛选器为键,而与筛选器关联的数据为值。筛选器数据可用于指示当消息与筛选器匹配时要采取的操作,筛选器数据的类型是筛选器表类的泛型参数。 筛选器数据可以包含路由规则、会话安全状态、通道上的侦听器等等。所有的消息筛选器都存储在实现了IMessageFilterTable<TFilterData>的表中,如MessageFilterTable<TFilterData>,在它的内部,又有很多个与具体筛选器类型相关的筛选器表,添加筛选器时,会将其放置在包含此类筛选器的内部筛选器表(如果已存在)中。如果不存在此筛选器表,则调用 CreateFilterTable 以分配一个适当类型的新筛选器表,如图3所示:

图3

同时在添加筛选器时,筛选器表会给每个筛选器设置一个默认的优先级。

设置服务的消息筛选器

我们可以通过ServiceBehavior来指定服务所用的消息筛选器,在ServiceBehavior中有一个AddressFilterMode的属性,它用来指定调度程序用于将传入的消息路由到匹配的终结点,由三个选项:

Exact:指示对传入消息的地址执行精确匹配的筛选器,即使用EndpointAddressMessageFilter。

Prefix:指示对传入消息的地址执行最长前缀匹配的筛选器,即使用PrefixEndpointAddressMessageFilter。

Any:指示与传入消息的任意地址相匹配的筛选器,即使用MatchAllMessageFilter。

如下面的代码,指示使用PrefixEndpointAddressMessageFilter作为地址筛选器:

[ServiceBehavior(AddressFilterMode = AddressFilterMode.Prefix)]
public class CalculatorService : ICalculator
{public int Add(int x, int y){return x + y;}
}
我们可以在Host端输出一下EndpointDispatcher所用的地址筛选器和契约筛选器,如下代码所示:

static void Main(string[] args)
{using (ServiceHost calculatorServiceHost =new ServiceHost(typeof(CalculatorService))){calculatorServiceHost.Opened += delegate{Console.WriteLine("Service begin to listen via the Address:{0}",calculatorServiceHost.BaseAddresses[0].ToString());};calculatorServiceHost.Open();foreach (ChannelDispatcher channelDispatcher incalculatorServiceHost.ChannelDispatchers){Console.WriteLine(channelDispatcher.BindingName);foreach (EndpointDispatcher endpointDispatcher inchannelDispatcher.Endpoints){Console.WriteLine(endpointDispatcher.AddressFilter.ToString());Console.WriteLine(endpointDispatcher.ContractFilter.ToString());}Console.WriteLine("---------------------------");}Console.Read();}
}
输出结果如图4所示:

图4

结束语

本文详细介绍了WCF中的消息筛选器,这在某些场景下非常有用,可以根据SOAP消息标头中包含的数据将消息发送到不同的地方处理,这在一定程度上可以摆脱WCF的调度模型。WCF寻址相关文章:
WCF专题系列(5):深入WCF寻址Part 5—逻辑地址和物理地址
WCF专题系列(4):深入WCF寻址Part 4—自定义消息筛选器
WCF专题系列(2):深入WCF寻址Part 2—自定义寻址报头
WCF专题系列(1):深入WCF寻址Part 1—Web服务寻址规范
本文转自lihuijun51CTO博客,原文链接:http://blog.51cto.com/terrylee/151933 ,如需转载请自行联系原作者

TerryLee技术专栏WCF后传正文 WCF后传系列(3):深入WCF寻址Part 3—消息过滤引擎...相关推荐

  1. WCF后传系列(3):深入WCF寻址Part 3—消息过滤引擎

    概述 通过前面两篇的介绍,对Web服务寻址规范以及在WCF开发中终结点地址有了深入的认识.本文我们继续深入WCF寻址第三部分内容,当消息传入时,如何来确定匹配的终结点,就是我们本文要讲到的消息筛选引擎 ...

  2. WCF分布式开发步步为赢(0):WCF学习经验分享,如何更好地学习WCF?

    WCF分布式开发学习,应该从哪里开始? 微软WCF Web服务 Web API学习群 339444457 微软ASP.NET MVC 4 Web编程群     44206115 学习WCF是不是就不需 ...

  3. WCF系列教程之WCF客户端调用服务

    1.创建WCF客户端应用程序需要执行下列步骤 (1).获取服务终结点的服务协定.绑定以及地址信息 (2).使用该信息创建WCF客户端 (3).调用操作 (4).关闭WCF客户端对象 二.操作实例 1. ...

  4. [zz]WCF分布式开发步步为赢(0):WCF学习经验分享,如何更好地学习WCF?

    WCF分布式开发学习,应该从哪里开始?    学习WCF是不是就不需要学习Enterprise Sevices(COM+).Net Remoting.Web Service(ASMX).WSE3.0和 ...

  5. WCF学习经验分享,如何更好地学习WCF?

    WCF分布式开发学习,应该从哪里开始? 学习WCF是不是就不需要学习Enterprise Sevices(COM+).Net Remoting.Web Service(ASMX).WSE3.0和MSM ...

  6. 【重要】有三AI技术专栏作者邀请,5大权益助力共同成长

    知识分享平台众多,我们有三AI公众号是其中一个,在过去的3年里,我们已经写了700多篇,超过200万字的技术文,其中一些专栏作者的贡献功不可没.我们公众号只做原创内容,因为我并不希望平台成为一个靠复制 ...

  7. java metrics.counter_技术专栏 | 深入理解Metrics(二):Counters

    原标题:技术专栏 | 深入理解Metrics(二):Counters 本章会继续讲解Metrics的第二个工具:Counters. 1. Counters的使用 在account内部使用Counter ...

  8. 【历史上的今天】3 月 27 日:《华尔街日报》技术专栏作家出生;AMD 推出 K5 处理器;匈牙利数理逻辑的奠基人诞生

    整理 | 王启隆 透过「历史上的今天」,从过去看未来,从现在亦可以改变未来. 今天是 2022 年 3 月 27 日,在 2010 年的今天,浙江吉利控股集团有限公司与美国福特汽车公司在沃尔沃总部所在 ...

  9. 【Web技术】1016- 全面理解 8 种文件上传场景

    在日常工作中,文件上传是一个很常见的功能.在项目开发过程中,我们通常都会使用一些成熟的上传组件来实现对应的功能.一般来说,成熟的上传组件不仅会提供漂亮 UI 或好的交互体验,而且还会提供多种不同的上传 ...

最新文章

  1. 始于《将才》,而不止于将才
  2. Method-Swizzling实战-实现iOS原生网络请求性能采集
  3. img标签设置display:block,宽度无法100%
  4. 下列有关计算机系统叙述正确,()下列有关计算机系统软件的叙述正确的是____
  5. mac下,vagrant桥接,选择“en0: 以太网”无法启动虚拟机解决方案
  6. 新手学Docker(1)Hello World
  7. mysql操作--json/数组 的增删该查
  8. 计算机应用基础 项目4-5 分析商品销售业绩 ppt课件,计算机应用基础课件项目四汇总.ppt...
  9. MySQL 之1045错误
  10. 我的世界服务器如何修改天气,我的世界天气修改设置、天气关闭锁定、天气指令代码作弊码大全-66街机网...
  11. 第二次上机作业 (数组综合)
  12. 服务器维护之后大角会刷新吗,魔兽世界大角刷新最具体时间 准确率达95%
  13. vue项目中 集成plus
  14. 日本儒学的特色与日本文化
  15. 科珀尼克:非营利项目回顾展
  16. 春季高考山东招生学校计算机,2017年山东春季高考信息技术专业本科招生院校...
  17. SSM整合的一些细节问题
  18. IT机房运维技术五大体系
  19. AI Benchmark v4榜首风云:海思麒麟9000登上榜首
  20. 一文读懂ARM技术架构(转)

热门文章

  1. “二子乘舟”的故事很难讲
  2. WF4.0进行单元测试
  3. element-ui中el-tree树形控件-树节点的选择(选中当前节点,获取当前id并且获取其父级id)...
  4. Go语言开发者福利 - 国内版 The Go Playground
  5. 无序列表属性 隐藏方式 JS简介
  6. Oracle计划将ZGC项目提交给OpenJDK
  7. 联想筹资13.5亿美元 支付收购摩托罗拉移动剩余款
  8. vue中props的双向绑定
  9. css实现文字超出显示省略号...
  10. 使用ajax和history.pushState无刷新改变页面URL