Service Versioning using WCF Routing

20-06-2013
source code

Introduction

In this sample code I will build WCF Routing service to explain how we can acheive service versioning using WCF Routing Service. I will create two services with the same service contract but with two different implementations. I will also build a client that will call these services using the routing service.

The Services

ServiceVersion1 and ServiceVersion1 are sharing the same contract but with two different implemntations for the same contract. Here is the listing that shows both services and the contract they are implementing

IVersionService contract

[ServiceContract]
 public interface IVersionService
 {
  [OperationContract]
  string GetMessage();
 }

ServiceVersion1 listing

public class ServVersion1 : IVersionService
 {
  public string GetMessage()
  {
   return "Your response from version 1";
  }
 }

ServiceVersion2 listing

public class ServVersion2 : IVersionService
 {
  public string GetMessage()
  {
   return string.Format("Your response from version 2");
  }
 }

The binding for both services is the default basicHttpBinding. As you can see the contract contains one method which is GetMessage. Each service in return implements this method by returning a different message so we know which service we are calling. This is important when we test Routing so we know that we can actually call two different versions from the same service without the client being involved in any kind of change to their configurations

The Routing Service

All the work of the Routing Service is being controlled from the configuration settings, as such there is no implementation for this service. Here is the listing for the Routing service

<%@ ServiceHost="" Language="C#" Debug="true" 
 Service="System.ServiceModel.Routing.RoutingService, System.ServiceModel.Routing, version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" %>

Note how this Service property of the ServiceHost tag is being assigned to System.ServiceModel.Routing.RoutingService. This feature of having ready made configuration or implementation for common scenarios is common in WCF. This will increase your productivity as you don't have to implement everything from scratch unless your needs doesn't fit in any of the implemented scenarios

WCF Routing Service Configuration

The WCF Routing service configuration is similar to any WCF service configuration but with the additional information that the Routing service needs to forward the incomming calls. Here is the listing of WCF Routing service config file which we will be using in this sample code

<system.serviceModel>
    <bindings>
      <wsHttpBinding>
        <binding name="RoutingServBindings">
          <security mode="None" />
        </binding>
      </wsHttpBinding>
    </bindings>
    <client>
      <endpoint address="http://localhost:52767/ServVersion1.svc" binding="basicHttpBinding"
        contract="*" name="ServVersion1EndPoint" />
      <endpoint address="http://localhost:52768/ServVersion2.svc" binding="basicHttpBinding"
        contract="*" name="ServVersion2EndPoint" />
    </client>
    <services>
      <service behaviorConfiguration="routingConfiguration"
               name="System.ServiceModel.Routing.RoutingService">
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:52771/RouterServ.svc" />
          </baseAddresses>
        </host>
        <!--Set up the inbound endpoint for the Routing Service-->
        <endpoint address="RouteMyCall"
                  binding="wsHttpBinding" bindingConfiguration="RoutingServBindings"
                  name="routeServEndpoint"
                  contract="System.ServiceModel.Routing.IRequestReplyRouter" />
      </service>
    </services>
    <behaviors>
      <!--default routing service behavior definition-->
      <serviceBehaviors>
        <behavior name="routingConfiguration">
          <routing filterTableName="filterTable1" />
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="true"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <routing>
      <namespaceTable>
        <add prefix="custom" namespace="http://service.versions.namespace/"/>
      </namespaceTable>
      <filters>
        <filter name="XPathFilter" filterType="XPath" filterData="sm:header()/custom:VersionSelector = 1"/>
        <filter name="MatchAllFilter" filterType="MatchAll" />
      </filters>
      <filterTables>
        <filterTable name="filterTable1">
          <add filterName="XPathFilter" endpointName="ServVersion1EndPoint" priority="1"/>
          <add filterName="MatchAllFilter" endpointName="ServVersion2EndPoint" priority="0"/>
        </filterTable>
      </filterTables>
    </routing>
  </system.serviceModel>

We are using wsHttpBinding and setting the security mode to none for simplicity. We are also adding two endpoints so we can call ServiceVersion1 and ServiceVersion2. We are then defining our Routing service. Note how we are using the System.ServiceModel.Routing.IRequestReplyRouter interface as our contract which inturn implemented by System.ServiceModel.Routing.RoutingService. In the tag we added our filterTableName inside the table. Finally we need to define our filter table. This filter will define the rules that the routing service will use to know where to forward the incomming calls. We are using two different kinds of filters. XPathFilter and MatchAllFilter. XPathFilter will look for the VersionSelector property in the incomming message header. If the value of this property is 1 then the incoming call will be forwarded to ServiceVersion1 otherwise the MatchAllFilter will be applied. The MatchAllFilter will be applied to all incomming calls. here we are forwarding these calls to ServiceVersion2. Note how we are setting priority in our filter table definition. This will tell the Routing Service to use filter with the highest priority on wards. Note that if the routing service failed to find any match for XPathFilter then it will use the next filter in priority and in this example it will be the MatchAllFilter filter.

The Client

The first step when setting a client for routing service is to add a reference to one of the target services i.e. ServiceVersion1 or ServiceVersion2 so you have the contact. Note that you will only have one end point that will target the Routing Service but adding a reference to the. Here is the config file for our Service Routing client along with its implementation

WCF Service Routing Client config

<system.serviceModel>
    <bindings>
      <wsHttpBinding>
        <binding name="RoutingServClientBindings">
          <security mode="None" />
        </binding>
      </wsHttpBinding>
    </bindings>
    <client>
      <endpoint address="http://localhost:52771/RouterServ.svc/RouteMyCall" binding="wsHttpBinding"
          bindingConfiguration="RoutingServClientBindings" contract="ServVersion1Ref.IVersionService"
          name="RoutingServiceClientEndPoint" />
    </client>
  </system.serviceModel>

Note how we are using the contract IVersionService which is used in both ServiceVersion1 and ServiceVersion2 but we are pointing to the routing service instead

WCF Service Routing Client implementation

var routerClient = new ServVersion1Ref.VersionServiceClient();
 using (OperationContextScope scope =
 new OperationContextScope(routerClient.InnerChannel))
 {
   OperationContext.Current.OutgoingMessageHeaders.Add(
   MessageHeader.CreateHeader(
   "VersionSelector",
   "http://service.versions.namespace/",
   "1"));
   Response.Write(routerClient.GetMessage());
 }
 routerClient.Close();

Note how we are adding the VersionSelector property to the header of the outgoing message so the routing service can decide where to route the call. If we set this to 2 or if we don't set it at all then the call will be forwarded to ServiceVersion2 because the MatchAllFilter will be matched.

The following diagram explains the communication between these various services and the client

Figure 1: Service Versioning with WCF Routing Service

Summary

WCF Routing Service was introduced in WCF 4.0. One of the useful application of this type of services is implementing service versioning. This sample code explained the various aspects of implementing service versioning using WCF Routing Service.