自定义消息筛选器

MessageFilter 示例演示如何替换 Windows Communication Foundation (WCF) 用于将消息调度到终结点的消息筛选器。

注释

本示例的设置过程和生成说明位于本主题末尾。

当通道上的第一条消息到达服务器时,服务器必须确定与该 URI 关联的终结点中(如果有)哪些应接收该消息。 此过程受附加到 MessageFilterEndpointDispatcher 对象控制。

服务的每个终结点都有一个 EndpointDispatcherEndpointDispatcher 同时具有 AddressFilterContractFilter。 这两个筛选器的合并是用于该终端的消息筛选器。

默认情况下,终结点 AddressFilter 会匹配任何发送到与服务终结点 EndpointAddress 匹配的地址的消息。 默认情况下,终结点 ContractFilter 检查传入消息的动作,并将任何消息与服务终结点契约的操作之一的动作相匹配(只考虑 IsInitiating=true 动作)。 因此,默认情况下,仅当消息的 To 标头为终结点的 EndpointAddress 并且消息的动作与终结点操作的动作之一匹配时,终结点的筛选器才与此消息匹配。

可以使用行为更改这些筛选器。 在示例中,该服务创建了一个IEndpointBehavior,它替换了AddressFilterContractFilter上的EndpointDispatcher

class FilteringEndpointBehavior : IEndpointBehavior
{
    //...
}

定义了两个地址筛选器:

// Matches any message whose To address contains the letter 'e'
class MatchEAddressFilter : MessageFilter { }
// Matches any message whose To address does not contain the letter 'e'
class MatchNoEAddressFilter : MessageFilter { }

FilteringEndpointBehavior 可以进行配置,并允许两种不同的变体。

public class FilteringEndpointBehaviorExtension : BehaviorExtensionElement { }

变体 1 仅匹配包含“e”且具有任何行动的地址,而变体 2 仅匹配缺少“e”的地址。

if (Variation == 1)
    return new FilteringEndpointBehavior(
        new MatchEAddressFilter(), new MatchAllMessageFilter());
else
    return new FilteringEndpointBehavior(
        new MatchNoEAddressFilter(), new MatchAllMessageFilter());

在配置文件中,服务注册新行为:

<extensions>
    <behaviorExtensions>
        <add name="filteringEndpointBehavior" type="Microsoft.ServiceModel.Samples.FilteringEndpointBehaviorExtension, service" />
    </behaviorExtensions>
</extensions>

然后,服务为每个变体创建 endpointBehavior 配置:

<endpointBehaviors>
    <behavior name="endpoint1">
        <filteringEndpointBehavior variation="1" />
    </behavior>
    <behavior name="endpoint2">
        <filteringEndpointBehavior variation="2" />
    </behavior>
</endpointBehaviors>

最后,服务的端点引用其中之一behaviorConfigurations:

<endpoint address=""
        bindingConfiguration="ws"
        listenUri=""
        binding="wsHttpBinding"
        contract="Microsoft.ServiceModel.Samples.IHello"
        behaviorConfiguration="endpoint2" />

客户端应用程序的实现非常简单,它为服务的 URI 创建了两个通道(通过将该值作为第二个参数 (via) 传递给 CreateChannel(EndpointAddress)),并在每个通道上发送一条消息,同时为每个通道使用不同的终结点地址。 因此,来自客户端的出站消息具有不同的 To 指定,服务器会相应地响应,如客户端的输出所示:

Sending message to urn:e...
Exception: The message with To 'urn:e' cannot be processed at the receiver, due to an AddressFilter mismatch at the EndpointDispatcher. Check that the sender and receiver's EndpointAddresses agree.

Sending message to urn:a...
Hello

更改服务器配置文件中的变种会导致过滤器被替换,客户端会看到相反的行为(发送给urn:e的消息成功,而发送给urn:a的消息失败)。

<endpoint address=""
          bindingConfiguration="ws"
          listenUri=""
          binding="wsHttpBinding"
          contract="Microsoft.ServiceModel.Samples.IHello"
          behaviorConfiguration="endpoint1" />

设置、生成和运行示例

  1. 要生成解决方案,请按照生成 Windows Communication Foundation 示例中的说明进行操作。

  2. 若要在单机环境下运行示例,请按照 运行 Windows Communication Foundation 示例中的说明进行操作。

  3. 若要在跨计算机配置中运行示例,请按照 运行 Windows Communication Foundation 示例 中的说明作,并在Client.cs中更改以下行。

    Uri serviceVia = new Uri("http://localhost/ServiceModelSamples/service.svc");
    

    将 localhost 替换为服务器的名称。

    Uri serviceVia = new Uri("http://servermachinename/ServiceModelSamples/service.svc");