In "What's New in WCF 4.0?" I provided an overview of the core new features forthcoming in WCF 4.0 (to be released with Visual Studio 2010). As promised, I'll be exploring these features in this column starting in this article with the RouterService introduced in WCF 4.0. I should point out that I m basing this article on the PDC bits released in October 2009. These bits include a version of the RouterService called the ForwardingService reported to be renamed to RouterService before the release of .NET 4.0. For more information on WCF, see "Security Practices for WCF" and "Implementing SOA Patterns with WCF and .NET 4.0."

Why a RouterService?

A software router does not replace the importance of appropriate software or hardware load balancers within your network infrastructure. It is, however, quite useful in situations where the use of a preexisting software or hardware load balancer is not an option, or as a refinement beyond load balancing for application-specific distribution of messages. Thus, the following are possibly good uses for a software router like the RouterService:

  • Load balancing with custom heuristics not provided by traditional software or hardware load balancers.
  • Introducing a security boundary to receive messages within the DMZ and forward safely to downstream services behind the DMZ.
  • Priority routing to application pools or servers according to message content.
  • Message redirection for service versioning according to message content.
  • Any number of other content-based routing scenarios.
  • Partitioning services so that messages targeting operations can be handled by different application pools or servers.

Implementing a custom router for any of these scenarios using WCF 3.x turns out to be a lot of work. The increased demand for custom routers thus led to WCF 4.0 including a concrete implementation of a router that can handle messages over any protocol, with different messaging patterns (one-way, two-way, duplex), and with a convenient filtering configuration.

RouterService Architecture

From a high level, the purpose of the RouterService is to receive messages from clients and forward those messages to the appropriate downstream services. A particular RouterService instance is associated with a set of filtering rules (a filter table and a set of filters) that are inspected prior to forwarding the message. Filtering rules are at the heart of the RouterService because they determine the appropriate downstream service endpoint for each message. Downstream services may be hosted on the same machine as the router, or distributed across several machines in a server farm. Figure 1 illustrates this architecture.

Figure 1: High-level view of the RouterService architecture

Follow these steps to put the RouterService to use:

  • Choose a suitable hosting environment.
  • Expose one or more endpoints for clients.
  • Determine the appropriate binding configuration for each endpoint.
  • Configure the filter table and related filters to control routing.

I ll walk through these steps in the remainder of this article.

Hosting the RouterService

The RouterService is a WCF service implementation and, thus, can be self-hosted or hosted in IIS like any other service. If the RouterService will be hosted in a client application, you ll typically host the service in a Windows client (Windows Forms or WPF) and usually communicate over TCP or Named Pipes. If the RouterService will be hosted in a server deployment, your choice of IIS or a Windows Service will depend on the operating system. For Windows Server 2003 machines you ll likely use IIS 6 for HTTP access and a Windows Service for TCP. For Windows Server 2008 machines you ll use IIS 7 and the Windows Process Activation Service (WAS) for all protocols. The point here is that you can choose any hosting environment according to application requirements.

The RouterService is located in the Microsoft.ProcessServer.Messaging assembly and is part of the Microsoft.ProcessServer.Messaging namespace (this may change). The code to self-host the service then requires a reference to that assembly and the appropriate ServiceHost initialization code, as follows:

using (ServiceHost host = new ServiceHost(typeof(

Microsoft.ProcessServer.Messaging.RouterService)))

{

host.Open();

Console.WriteLine("Press <ENTER> to terminate Router Host");

Console.ReadLine();

}

You must provide a .svc endpoint for the RouterService type if you host the service with IIS:

<%@ ServiceHost Service=

"Microsoft.ProcessServer.Messaging.RouterService" %>

Router Endpoints and Contracts

Regardless of the host, you ll need to supply endpoints for the router in the service model configuration section. The following code snippet illustrates a <service> section that exposes an HTTP endpoint for the RouterService:

<service name="Microsoft.ProcessServer.Messaging.

RouterService" behaviorConfiguration="serviceBehavior">

<endpoint address=" " contract="Microsoft.

ProcessServer.Messaging.IRequestReplyDatagram"

binding="basicHttpBinding" />

</service>

This endpoint is associated with the IRequestReplyDatagram service contract implemented by the RouterService. Because the router must be able to process messages with any SOAP action, this contract includes a single, catch-all operation with an Action and ReplyAction set to * :

[ServiceContract(SessionMode = SessionMode.Allowed)]

public interface IRequestReplyDatagram

{

[OperationContract(Action = "*", ReplyAction = "*")]

Message ProcessMessage(Message message);

}

The RouterService also implements other contracts to support one-way and duplex communication, with similar settings to support any SOAP action. You may, for example, expose a router endpoint that can handle duplex communication (callbacks) between clients and services. This endpoint would rely on the IDuplexSession contract:

<endpoint address=" " contract="Microsoft.

ProcessServer.Messaging.IDuplexSession"

binding="customBinding" bindingConfiguration="router" />

The IDuplexSession contract defines a callback contract named ISimplexSession. These contracts also support any SOAP action, in addition to requiring sessions (as shown in Figure 2).

[ServiceContract(SessionMode=SessionMode.Required,

CallbackContract=typeof(ISimplexSession))]

public interface IDuplexSession

{

[OperationContract(IsOneWay=true, Action="*")]

void ProcessMessage(Message message);

}

[ServiceContract(SessionMode=SessionMode.Required)]

public interface ISimplexSession

{

[OperationContract(IsOneWay=true, Action="*")]

void ProcessMessage(Message message);

}

Figure 2: The IDuplexSession contract defines a callback contract named ISimplexSession

Configuring Filters

Filter configuration is the heart of the RouterService. As clients send messages to router endpoints, the RouterService evaluates filters to determine how to forward the message. This is done by associating a forwarding behavior with the service type, as shown in Figure 3.

<services>

<service name="Microsoft.ProcessServer.Messaging.

RouterService" behaviorConfiguration="serviceBehavior">

<endpoint address=" " contract="Microsoft.

ProcessServer.Messaging.IRequestReplyDatagram"

binding="basicHttpBinding" />

</service>

</services>

<behaviors>

<serviceBehaviors>

<behavior name="serviceBehavior">

<forwardingBehavior filterTableName="filterTable1"

filterOnHeadersOnly="true" />

</behavior>

</serviceBehaviors>

</behaviors>

Figure 3: Filter configuration is the heart of the RouterService

The forwarding behavior points to a filter table that lists relevant filters to evaluate as requests are processed by the RouterService. To optimize processing you can restrict filtering to message headers rather than processing the entire body of the message assuming the body of the message isn t required for filtering.

The filter table includes a list of filters to evaluate, indicating the priority level of each filter and the client endpoint to use if the filter evaluates to true. Filters are processed in order of priority; the first filter to match the incoming message is used to forward the message. The RouterService includes the necessary code to construct a proxy based on the appropriate client endpoint. This filtering architecture is illustrated in Figure 4.

Figure 4: Filtering architecture

Figure 5 shows a sample filter configuration. The priority 1 filter is examined before the priority 0 filter. The filter type for the priority 1 filter performs an XPath evaluation searching for a LicenseKey header. If the LicenseKey header matches the value XXX , messages are forwarded to the priority host indicated by the client endpoint configuration. If the LicenseKey header does not match, or a LicenseKey header is not present, the catch-all filter matches, and messages are sent to the default host.

<system.serviceModel>

<client>

<endpoint name="priorityHost" address=

http://localhost:8001/MessageManagerService

binding="customBinding" bindingConfiguration=

"router" contract="*"/>

<endpoint name="defaultHost" address=

http://localhost:8000/MessageManagerService

binding="customBinding" bindingConfiguration=

"router" contract="*"/>

</client>

<filtering>

<namespaceTable>

<add prefix="tig" namespace=

"http://www.thatindigogirl.com/samples/

2008/01" />

</namespaceTable>

<filters>

<filter name="defaultFilter" filterType=

"MatchAll" />

<filter name="priorityFilter" filterType=

"XPath" filterData="/s12:Envelope/

s12:Header/tig:LicenseKey = 'XXX'" />

</filters>

<filterTables>

<table name="filterTable1">

<filters>

<add filterName="defaultFilter" mappedValue=

"defaultHost" priority="0"/>

<add filterName="priorityFilter" mappedValue=

"priorityHost" priority="1"/>

</filters>

</table>

</filterTables>

</filtering>

</system.serviceModel>

Figure 5: RouterService filtering configuration

There are several useful filter types from which to choose, including:

  • MatchAll: Useful as a priority 0 filter in the event other filters do not match.
  • XPath: Used to match header or body elements to a particular value.
  • Action: Used to route based on the SOAP action of a message.
  • And: Used to combine filters before a match can be satisfied.
  • Custom: Used to supply a custom filtering component where you have programmatic control of the filter result.

Binding Configuration

The router typically does not process protocol headers passed by the client, as they are intended for the downstream service. As such, the router binding should purposely omit settings for security, reliable sessions, transactions, and other related protocols. The example I demonstrated earlier showed a router endpoint using BasicHttpBinding which, by default, does not enable security on any other protocols. You can achieve a raw router binding for HTTP or TCP using a CustomBinding configuration, as shown here:

<customBinding >

<binding name="routerHttp">

<httpTransport />

</binding>

<binding name="routerTcp">

<tcpTransport />

</binding>

</customBinding>

This means the router will forward messages without processing protocol headers; in theory, this means that clients can pass security headers without issue. The catch is that the router automatically adjusts the To header (a WS-Addressing header), which causes problems because the modified To header will no longer be signed something the service will expect if security is enabled. For HTTP requests, you can disable the modification of the To header by setting manual addressing to true, as shown here:

<customBinding >

<binding name="routerHttp">

<httpTransport manualAddressing="true"/>

</binding>

</customBinding>

Note: Manual addressing is not supported over TCP for two-way messaging. I discussed issues like this in the following MSDN articles related to building a custom WCF 3.x router:

Conclusion

The new RouterService to be released with WCF 4.0 removes the pain of building a custom router for the majority of pass-through router scenarios where messages are to be forwarded without processing based on application heuristics. In this article I explained the fundamentals of this new RouterService based on the PDC bits. The code samples accompanying this article illustrate many different filtering scenarios, and will be updated as new releases are available.

Download the samples for this article at www.dasblonde.net/downloads/asppromay09.zip.