Working with the .NET Framework 4.0 Windows Communication Foundation (WCF) Routing Service

Introduction

Often an integration solution requires some layer of indirection or mediation to handle things like security, versioning, and exceptions. Message Routing is a common pattern employed to handle such mediation. In .NET Framework 4.0, Windows Communication Foundation (WCF) now includes a Routing Service that encapsulates the Message Routing pattern.

Utilizing various routing service samples, this article will take a deep dive into the Routing Service showing how the Routing Service can be a solution for some common scenarios. Before delving into sample code some routing service architectural overview is in order.

Architectural Overview

A complete introduction to Routing Service and WCF architecture is beyond the scope of this article, so I’m going to center on where the Routing Service fits inside of WCF. If you’ve done work with WCF, you’ve probably seen the diagram below.

WCF routing service diagram
Figure 1: WCF components
Source

Recall that behaviors modify how the WCF Runtime behaves when a message travels out of the channel stack and the channel stack, composed of things like the binding, handle message transfer. Through Behaviors and accompanying extensibility points a developer can, for example, control how parts of WCF eventually invoke a proxy.

The routing service looks no different than any other WCF application. Since its operations are concerned with message contents and dispatching to proxies, it implements custom behaviors and WCF Runtime extensibility rather than a custom channel. Routing Service is composed of two parts: a Routing Service Type aptly named RoutingService and Service Behaviors applied to the host via a RoutingServiceConfiguration class.

With some context around where the routing service fits within WCF, looking at code will show how the routing service is used. Instead of creating an entirely new sample I’ll walk through three SDK samples and explain how each sample works. First, I’ll provide an overview of each sample and describe some common scenarios the pattern’s applied in the sample relate to.

Samples Overview

There are a number of routing service samples among the WCF samples shipping with the SDK. You can download the sample here. The samples this article focuses on can be found in the “Basic\Routing Service” folder under the “WCF” samples folder. Here is a summary of each sample and a short description of the routing service functionality the sample demonstrates. All of the samples leverage the ubiquitous WCF Calculator Service.

  • HelloRoutingService – This sample simply demonstrates how to configure the routing service. In the sample the routing service serves as a layer of indirection that passes a message on to another service.
  • RouterBridgingandErrorHandling – As in the HelloRoutingService sample, this sample is a layer of indirection. The sample demonstrates two scenarios. The first is bridging protocols, exposing an HTTP binding to a client, but accessing a service using NetTcp binding. The second scenario is providing a failover EndPoint when the primary EndPoint fails.
  • AdvancedFilters – Like the samples above, this sample performs some mediation. The sample also leverages filter tables, examining the contents of a message and passing the message on to the appropriate service based on contents. Scenarios captured in the sample can apply to Service aggregation; exposing a set of services as a single EndPoint. Other scenarios covered by the sample include: service versioning and security.

In all the samples the RoutingService sits between the CalculatorService on the backend and the CalculatorClient. The samples contain configuration (app.config) and code configuration. I’ll explain the samples from the code configuration perspective.

Now it’s time for a deep dive into each sample.

HelloRoutingService

Below are key parts of code from the HelloRoutingService sample. As I stated earlier this sample shows how to wire up the routing service.

  using (ServiceHost serviceHost =
      new ServiceHost(typeof(RoutingService)))
  {
      string clientAddress = "http://localhost:8000/servicemodelsamples/service";
      string routerAddress = "http://localhost:8000/routingservice/router";

      Binding routerBinding = new WSHttpBinding();
      Binding clientBinding = new WSHttpBinding();

      serviceHost.AddServiceEndpoint(typeof(IRequestReplyRouter), routerBinding, routerAddress);
      ContractDescription contract = ContractDescription.GetContract(typeof(IRequestReplyRouter));
      ServiceEndpoint client = new ServiceEndpoint(contract, clientBinding, new EndpointAddress(clientAddress));

      RoutingConfiguration rc = new RoutingConfiguration();
      List<ServiceEndpoint> endpointList = new List<ServiceEndpoint>();
      endpointList.Add(client);

      rc.FilterTable.Add(new MatchAllMessageFilter(), endpointList);

      serviceHost.Description.Behaviors.Add(new RoutingBehavior(rc));

      serviceHost.Open();
      // The service can now be accessed.
      Console.ReadLine();

  }

There are primarily two parts to the routing service: the RoutingService class and some custom behaviors. Looking at how the RoutingService class is defined reveals some interesting facts. The RoutingService class definition appears below.

       [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
       [ServiceBehavior(AddressFilterMode = AddressFilterMode.Any, InstanceContextMode = InstanceContextMode.PerSession, UseSynchronizationContext = false, ValidateMustUnderstand = false)]
       public sealed class RoutingService : ISimplexDatagramRouter, ISimplexSessionRouter, IRequestReplyRouter, IDuplexSessionRouter, IDisposable
 

The most interesting parts in the definition are that the ServiceBehavior turns off some default WCF validation and the InstanceContextMode setting. Deactivated automatic behavior is captured in the AddressFilterMode, UseSynchronixationContext, and ValidateMustUnderstand settings.

InstanceContextMode set to PerSession indicates that the proxy instance that is associated to the client invoking the service is maintained until the client no longer needs the service. Typically, PerSession instance context is required for services storing some sort of state associated to the client. A complete explanation of InstanceContextMode and how it impacts a service is beyond the scope of this article. The “Resources” section at the end of this article contains some more complete information.

Another interesting aspect of the class definition are the interfaces it implements. As you may have observed the interfaces are associated with the message exchange pattern implemented by a service EndPoint. In the example, the EndPoint is associated with IRequestReplyRouter interface.

RoutingConfiguration contains all the pertinent information for the RoutingBehavior class. Included in the RoutingConfiguration is a FilterTable containing a MatcheAllMessageFilter class. Later in the article I’ll elaborate on the FilterTable, for now look at MatchAllMessageFilter as a sort of “pass-thru” for all Message classes.

HelloRoutingService contained the basics, a more advanced sample shows how the RoutingServices can perform protocol bridging and Failover.

More by Author

Must Read