为了实现基于内容的路由,路由服务使用 MessageFilter 用于检查消息的特定部分(例如地址、终结点名称或特定 XPath 语句)的实现。 如果 .NET Framework 4.6.1 未提供任何消息筛选器来满足你的需求,则可以通过创建新的基 MessageFilter 类实现创建自定义筛选器。
配置路由服务时,必须定义描述 FilterElement 类型的筛选器元素(对象),以及创建筛选器所需的任何支持数据,例如要在消息中搜索的特定字符串值。 请注意,创建筛选器元素仅定义单个消息筛选器;若要使用筛选器来评估和路由消息,还必须定义筛选器表(FilterTableEntryCollection)。
筛选器表中的每个条目都引用筛选器元素,并指定消息在消息与筛选器匹配时将路由到的客户端终结点。 筛选器表条目还允许指定备份终结点的集合(BackupEndpointCollection),该集合定义消息在发送到主终结点时传输失败时将传输到的终结点列表。 这些终结点将按指定的顺序进行尝试,直到一个终结点成功。
消息筛选器
路由服务使用的消息筛选器提供常见的消息选择功能,例如评估消息发送到的终结点的名称、SOAP作或消息发送到的地址或地址前缀。 筛选器还可以与 AND 条件联接,因此,仅当消息与这两个筛选器匹配时,消息才会路由到终结点。 还可以通过创建自己的实现 MessageFilter创建自定义筛选器。
下表列出了 FilterType 路由服务使用的类、实现特定消息筛选器的类和所需的 FilterData 参数。
| 筛选器类型 | DESCRIPTION | 筛选数据含义 | 示例筛选器 | 
|---|---|---|---|
| 行动 | 使用 ActionMessageFilter 类匹配包含特定操作的消息。 | 筛选器基于的操作。 | <filter name="action1" filterType="Action" filterData="http://namespace/contract/operation" /> | 
| 终端地址 | 使用 EndpointAddressMessageFilter 类,结合 IncludeHostNameInComparison == true匹配包含特定地址的消息。 | 筛选器基于的地址(在 To 标头中)。 | <filter name="address1" filterType="EndpointAddress" filterData="http://host/vdir/s.svc/b"  /> | 
| EndpointAddressPrefix | 使用 PrefixEndpointAddressMessageFilter 类,通过 IncludeHostNameInComparison == true匹配包含特定地址前缀的消息。 | 使用最长前缀匹配时要筛选的地址。 | <filter name="prefix1" filterType="EndpointAddressPrefix" filterData="http://host/" /> | 
| 和 | 使用始终在返回前计算两个条件的 StrictAndMessageFilter 类。 | 不使用 filterData;而 filter1 和 filter2 具有相应消息筛选器的名称(也在表中),应使用 AND 将它们连接起来。 | <filter name="and1" filterType="And" filter1="address1" filter2="action1" /> | 
| 习惯 | 一种用户定义的类型,用于扩展 MessageFilter 类,并具有采用字符串的构造函数。 | customType 属性是要创建的类的完全限定类型名称;filterData 是在创建筛选器时传递给构造函数的字符串。 | <filter name="custom1" filterType="Custom" customType="CustomAssembly.CustomMsgFilter, CustomAssembly" filterData="Custom Data" /> | 
| 端点名称 | 使用 EndpointNameMessageFilter 类根据到达的服务终结点的名称匹配消息。 | 服务终结点的名称,例如:“serviceEndpoint1”。 这应该是在路由服务上公开的终结点之一。 | <filter name="stock1" filterType="Endpoint" filterData="SvcEndpoint" /> | 
| MatchAll | 使用 MatchAllMessageFilter 类。 此筛选器匹配所有到达的消息。 | 不使用 filterData。 此筛选器将始终匹配所有消息。 | <filter name="matchAll1" filterType="MatchAll" /> | 
| XPath | 使用 XPathMessageFilter 类匹配消息中的特定 XPath 查询。 | 匹配消息时要使用的 XPath 查询。 | <filter name="XPath1" filterType="XPath" filterData="//ns:element" /> | 
以下示例定义使用 XPath、EndpointName 和 PrefixEndpointAddress 消息筛选器的筛选器条目。 此示例还演示了如何使用 RoundRobinFilter1 和 RoundRobinFilter2 条目的自定义筛选器。
<filters>  
     <filter name="XPathFilter" filterType="XPath"
             filterData="/s12:Envelope/s12:Header/custom:RoundingCalculator = 1"/>  
     <filter name="EndpointNameFilter" filterType="EndpointName"
             filterData="calculatorEndpoint"/>  
     <filter name="PrefixAddressFilter" filterType="PrefixEndpointAddress"
             filterData="http://localhost/routingservice/router/rounding/"/>  
     <filter name="RoundRobinFilter1" filterType="Custom"
             customType="RoutingServiceFilters.RoundRobinMessageFilter,
             RoutingService" filterData="group1"/>  
     <filter name="RoundRobinFilter2" filterType="Custom"
             customType="RoutingServiceFilters.RoundRobinMessageFilter,
             RoutingService" filterData="group1"/>  
</filters>  
注释
仅仅定义筛选器并不会使消息自动根据筛选器进行评估。 必须将筛选器添加到筛选器表中,然后将该表与路由服务公开的服务终结点关联起来。
命名空间表
使用 XPath 筛选器时,包含 XPath 查询的筛选器数据可能会由于命名空间的使用而变得非常大。 为了缓解此问题,路由服务提供了使用命名空间表定义自己的命名空间前缀的功能。
命名空间表是一个 NamespaceElement 对象集合,用于定义可在 XPath 中使用的常见命名空间的命名空间前缀。 以下是命名空间表中包含的默认命名空间和命名空间前缀。
| 前缀 | Namespace | 
|---|---|
| s11 | http://schemas.xmlsoap.org/soap/envelope | 
| s12 | http://www.w3.org/2003/05/soap-envelope | 
| wsaAugust2004 | http://schemas.xmlsoap.org/ws/2004/08/addressing | 
| wsa10 | http://www.w3.org/2005/08/addressing | 
| sm | http://schemas.microsoft.com/serviceModel/2004/05/xpathfunctions | 
| tempuri | http://tempuri.org | 
| 爵士 | http://schemas.microsoft.com/2003/10/Serialization | 
如果知道要在 XPath 查询中使用特定命名空间,则可以将其添加到命名空间表以及唯一的命名空间前缀,并在任何 XPath 查询中使用前缀,而不是完整命名空间。 以下示例定义命名空间 "http://my.custom.namespace"的前缀“custom”,该前缀随后在 filterData 中包含的 XPath 查询中使用。
<namespaceTable>  
     <add prefix="custom" namespace="http://my.custom.namespace/"/>  
</namespaceTable>  
<filters>  
     <filter name="XPathFilter" filterType="XPath" filterData="/s12:Envelope/s12:Header/custom:RoundingCalculator = 1"/>  
</filters>  
筛选表
尽管每个筛选器元素定义了可应用于消息的逻辑比较,但筛选器表提供筛选器元素与目标客户端终结点之间的关联。 筛选器表是一个命名的对象 FilterTableEntryElement 集合,用于定义筛选器、主目标终结点和备用备份终结点列表之间的关联。 筛选器表条目还允许为每个筛选条件指定可选优先级。 以下示例定义两个筛选器,然后定义一个筛选器表,该表将每个筛选器与目标终结点相关联。
<routing>  
     <filters>  
       <filter name="AddAction" filterType="Action" filterData="Add" />  
       <filter name="SubtractAction" filterType="Action" filterData="Subtract" />  
     </filters>  
     <filterTables>  
       <table name="routingTable1">  
         <filters>  
           <add filterName="AddAction" endpointName="Addition" />  
           <add filterName="SubtractAction" endpointName="Subtraction" />  
         </filters>  
       </table>  
     </filterTables>
</routing>  
筛选器计算优先级
默认情况下,所有筛选器表中的条目将被同时评估,且所评估的消息将被路由到与每个匹配的筛选器条目相关联的终结点。 如果多个筛选器的结果为true,并且消息是单向或双向,则消息将多播到符合条件的所有终结点。 请求回复消息不能进行多播,因为只能返回一个回复给客户端。
可以通过为每个筛选器指定优先级来实现更复杂的路由逻辑;路由服务首先评估优先级最高的所有筛选器。 如果消息与此级别的筛选器匹配,则不会处理优先级较低的筛选器。 例如,首先针对优先级为 2 的所有筛选器评估传入的单向消息。 该消息与此优先级级别的任何筛选器不匹配,因此,接下来将消息与优先级为 1 的筛选器进行比较。 两个优先级 1 筛选器与消息匹配,因为它是一个单向消息,因此它被路由到两个目标终结点。 由于在优先级 1 筛选器中找到匹配项,因此不会评估优先级 0 的筛选器。
注释
如果未指定优先级,则使用默认优先级 0。
以下示例定义一个筛选器表,该表指定表中引用的筛选器的优先级为 2、1 和 0。
<filterTables>  
     <filterTable name="filterTable1">  
          <add filterName="XPathFilter" endpointName="roundingCalcEndpoint"
               priority="2"/>  
          <add filterName="EndpointNameFilter" endpointName="regularCalcEndpoint"
               priority="1"/>  
          <add filterName="PrefixAddressFilter" endpointName="roundingCalcEndpoint"
               priority="1"/>  
          <add filterName="MatchAllMessageFilter" endpointName="defaultCalcEndpoint"
               priority="0"/>  
     </filterTable>  
</filterTables>  
在前面的示例中,如果消息符合 XPathFilter,则会将其路由到 roundingCalcEndpoint,并且表中不会进一步评估筛选器,因为所有其他筛选器的优先级较低。 但是,如果消息与 XPathFilter 不匹配,则会根据下一个较低优先级、EndpointNameFilter 和 PrefixAddressFilter 的所有筛选器进行评估。
注释
如果可能,请使用排他筛选器,而不是指定优先级,因为优先级评估可能会导致性能下降。
备份列表
筛选器表中的每个筛选器都可以选择指定一个备份列表,该列表是终结点的命名集合(BackupEndpointCollection)。 该集合包含在向主终结点(在 CommunicationException 中指定)发送消息期间发生 EndpointName 时,消息将传输到的终结点的有序列表。 以下示例定义一个名为“backupServiceEndpoints”的备份列表,其中包含两个终结点。
<filterTables>  
     <filterTable name="filterTable1">  
          <add filterName="MatchAllFilter1" endpointName="Destination" backupList="backupEndpointList"/>  
     </filterTable>  
</filterTables>  
<backupLists>  
     <backupList name="backupEndpointList">  
          <add endpointName="backupServiceQueue" />  
          <add endpointName="alternateServiceQueue" />  
     </backupList>  
</backupLists>  
在前面的示例中,如果发送到主终结点“目标”失败,路由服务将尝试按列出的顺序发送到每个终结点。首先发送到 backupServiceQueue,如果发送到 backupServiceQueue 失败,则发送到 alternateServiceQueue。 如果所有备份终结点都失败,则会返回错误。