Welcome to EMC Consulting Blogs Sign in | Join | Help

Owain Wraggs' Blog

I have now left EMC Consulting, you can subscribe to my new blog here: http://blog.endjin.com/author/owain-wragg/

Content Based Routing With WCF

I’ve been looking at the new features included in WCF 4, one of the most interesting and powerful additions is the functionality provided by the RoutingService class (System.ServiceModel.Routing.RoutingService) in this post I’ll show an example of how to perform content based routing using the RoutingService class.

The example scenario is as follows: orders are submitted to one of two services (both of which have the same contract), one service is responsible for processing low value orders (less than or equal to £5000) whilst the other service processes high value orders (over £5000). The reason two different services are required is that low value orders can be automatically processed whilst high value orders require human interaction to validate the order before the order can be processed. Ideally we do not want the client to know that there are two separate services and further to this we do not want them to be responsible for picking which service to send the order to, fortunately WCF 4 has functionality which enables a service to be exposed which will forward the request to another service based on the content of the request.

Shown below is Order Service contract

    [ServiceContract]

    public interface IOrderService

    {

        [OperationContract]

        void ProcessOrder(Order order);

    }

There are two implementations of this contract HumanWorkflowOrderService and StraightThroughProcessingOrderService, all these two services do is simply write out the details the received order to the Output window.

The service the clients call into, which performs the content based routing needs to host the RoutingService, in fact no code is required at all to implement content based routing shown below is the contents of the service host file (in this example RoutingService.svc)

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

 Next the content based routing needs to be configured so that when called the routing service knows where to forward the request to. Shown below is the service model configuration section.

  <system.serviceModel>

   

    <client>

      <endpoint address="http://localhost:1170/HumanWorkflowOrderService.svc"

                binding="basicHttpBinding" contract="*" name="BasicHttpBinding_HumanWorkflowOrderService" />

      <endpoint address="http://localhost:1170/StraightThroughProcessingOrderService.svc"

                binding="basicHttpBinding" contract="*" name="BasicHttpBinding_StraightThroughProcessingOrderService" />

    </client>

 

    <services>

      <service behaviorConfiguration="RoutingServiceBehavior"

        name="System.ServiceModel.Routing.RoutingService">

        <endpoint address="" binding="basicHttpBinding" name="RoutingServiceEndpoint" contract="System.ServiceModel.Routing.IRequestReplyRouter" />

      </service>

    </services>

 

    <behaviors>

      <serviceBehaviors>

        <behavior name="RoutingServiceBehavior">

          <serviceMetadata httpGetEnabled="true"/>

          <serviceDebug includeExceptionDetailInFaults="false" />

          <routing routingTableName="routingRules" filterOnHeadersOnly="false" />

        </behavior>

      </serviceBehaviors>

    </behaviors>

 

    <routing>

      <filters>

        <filter name="lessThan5kFilter" filterType="XPath" filterData="boolean(//*[local-name()= 'Price']/text() &lt;= 5000)"/>

        <filter name="greaterThan5kFilter" filterType="XPath" filterData="boolean(//*[local-name()= 'Price']/text() &gt; 5000)"/>

      </filters>

      <routingTables>

        <table name="routingRules">

          <entries>

            <add filterName="lessThan5kFilter" endpointName="BasicHttpBinding_StraightThroughProcessingOrderService"/>

            <add filterName="greaterThan5kFilter" endpointName="BasicHttpBinding_HumanWorkflowOrderService"/>

          </entries>

        </table>

      </routingTables>

    </routing>

   

  </system.serviceModel>

The import things to notice are that the RoutingService implements the System.ServiceModel.Routing.IRequestReplyRouter contract which provides request reply functionality; there are other contracts that you could use if you wanted your service to behave differently e.g. ISimpleSessionRouter, IDuplexSessionRouter etc.

The RoutingServiceBehavior includes the routing element which specifies what routing configuration to use (in our example “routingRules”) and also that content based routing can be performed on both the message header and message body.

Next if you look at the routing sections this specifies two filters which use XPath to perform the routing evaluation (there are a number of different filters available all of which derive from System.ServiceModel.Dispatcher.MessageFilter). These filters are then used in the table section which specifies that when the filter’s criteria are matched which endpoint should be called. So in the example when the “lessThan5kFilter”filter evaluates successfully the “BasicHttpBinding_StraightThroughProcessingOrderService” endpoint is called.

So as you can see using the new RoutingService it is very simple to configure your service to forward a message on to another service based on the content of the received message.

I’ve attached the solution to this post; the solution also contains a readme file which explains how to run the application.

Note: - That this post was written using Beta 1 of the .NET Framework 4.0 so therefore changes in future releases of the .NET Framework might break the example application

Comments

 

jamie.thomson said:

One more in the eye for the "XML is not a programming language" brigade :)

July 22, 2009 1:58 PM
Anonymous comments are disabled
Powered by Community Server (Personal Edition), by Telligent Systems