Custom Message Filter

The MessageFilter sample demonstrates how to replace the message filters that Windows Communication Foundation (WCF) uses to dispatch messages to endpoints.

Note

The setup procedure and build instructions for this sample are located at the end of this topic.

When the first message on a channel arrives at the server, the server must determine which (if any) of the endpoints associated with that URI should receive the message. This process is controlled by the MessageFilter objects attached to the EndpointDispatcher.

Each endpoint of a service has a single EndpointDispatcher. The EndpointDispatcher has both an AddressFilter and a ContractFilter. The union of these two filters is the message filter used for that endpoint.

By default, the AddressFilter for an endpoint matches any message that is addressed to an address that matches the service endpoint's EndpointAddress. By default, the ContractFilter for an endpoint inspects the action of the incoming message and matches any message with an action that corresponds to one of the actions of the service endpoint contract's operations (only IsInitiating=true actions are considered). As a result, by default, the filter for an endpoint only matches if both the message's To header is the EndpointAddress of the endpoint and the message's action matches one of the endpoint operation's actions.

These filters can be changed using a behavior. In the sample, the service creates an IEndpointBehavior that replaces the AddressFilter and ContractFilter on the EndpointDispatcher:

class FilteringEndpointBehavior : IEndpointBehavior
{
    //...
}

Two address filters are defined:

// 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 { }

The FilteringEndpointBehavior is made configurable and allows for two different variations.

public class FilteringEndpointBehaviorExtension : BehaviorExtensionElement { }

Variation 1 matches only addresses that contain an 'e' (but that have any Action) whereas Variation 2 matches only addresses that lack an 'e':

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

In the configuration file, the service registers the new behavior:

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

Then the service creates endpointBehavior configurations for each variation:

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

Finally, the service's endpoint references one of the behaviorConfigurations:

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

The implementation of the client application is straightforward; it creates two channels to the service's URI (by passing in that value as the second (via) parameter to CreateChannel(EndpointAddress) and sends a single message on each channel, but it uses different endpoint addresses for each. As a result, the outbound messages from the client have different To designations, and the server responds accordingly, as demonstrated by the client's output:

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

Switching the variation in the server's configuration file causes the filter to be swapped and the client sees the opposite behavior (the message to urn:e succeeds, whereas the message to urn:a fails).

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

To set up, build, and run the sample

  1. To build the solution, follow the instructions in Building the Windows Communication Foundation Samples.

  2. To run the sample in a single-machine configuration, follow the instructions in Running the Windows Communication Foundation Samples.

  3. To run the sample in a cross-machine configuration, follow the instructions at Running the Windows Communication Foundation Samples and change the following line in Client.cs.

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

    Replace localhost with the name of server.

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