Implementing content based routing using the Windows Application Server (Dublin) forwarding service

Dublin’s application server incorporates a series of runtimes services that complement the runtime behavior of a WCF service host on areas such as lifecycle, persistence, message routing, etc. Among those services, the forwarding services provides high performance message routing across different services. By providing a robust foundation for messaging routing, Dublin’s forwarding service can address really complex service composition and endpoint virtualization scenarios which are traditionally very hard to implement in real world SOA applications. Capabilities such as service aggregation, content-based routing, protocol translation or data partitioning are notorious for requiring a lot of infrastructure logic in order to work properly and consequently can be drastically simplified by the use of a technology like the forwarding service.

Dublin’s forwarding service proposes a versatile model for message routing based on the concepts of WCF filters and filter tables. This post does not intend to explain the intricacies of the forwarding service; instead we are going to explore a practical example of how to leverage this new technology to implement a traditional intelligent endpoint routing scenario.

Our scenario starts with a service hosted on multiple endpoints across a server farm. Messages targeted to that service will be routed to different endpoints depending on its content. Additionally, the rules that control the content can be subject to frequent changes that need to be incorporates without impacting the different endpoints. By using Dublin’s application service, we could conceive the following topology to address that scenario.

On this scenario, the forwarding service leverages XPath message filter and filter tables to dynamically route messages to the different service’s endpoints. For the simplicity of our example let’s assume our target service implements the following contract that processes a financial transaction.

 

   1:  [ServiceContract]
   2:  public interface IService
   3:  {
   4:   
   5:      [OperationContract]
   6:      bool ProcessTrasaction(Transaction transaction);
   7:   
   8:  }
   9:   
  10:  [DataContract]
  11:  public class Transaction 
  12:  {
  13:      private string transactionId;
  14:      private double amount;
  15:      private string customerId;
  16:   
  17:      [DataMember]
  18:      public string TransactionId
  19:      {
  20:          get { return transactionId; }
  21:          set { transactionId = value; }
  22:      }
  23:   
  24:      [DataMember]
  25:      public double Amount
  26:      {
  27:          get { return amount; }
  28:          set { amount = value; }
  29:      }
  30:   
  31:      [DataMember]
  32:      public string CustomerId
  33:      {
  34:          get { return customerId; }
  35:          set { customerId = value; }
  36:      }
  37:   
  38:  }

 

 

The service implementation not really relevant to this example. In order to distribute the message traffic we have decided to host the service on multiple endpoints as illustrated in the following configuration file.

   1:  ...
   2:      <services>
   3:              <service name="Service" behaviorConfiguration="ServiceBehavior">
   4:                  <!-- Service Endpoints -->
   5:                  <endpoint address="/ep1" binding="basicHttpBinding" contract="IService">
   6:          
   7:                      <identity>
   8:                          <dns value="my server"/>
   9:                      </identity>
  10:                  </endpoint>
  11:   
  12:          <endpoint address="/ep2" binding="basicHttpBinding" contract="IService">
  13:         
  14:            <identity>
  15:              <dns value="my server"/>
  16:            </identity>
  17:          </endpoint>
  18:   
  19:          <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
  20:              </service>
  21:          </services>
  22:  ...

No need to mention that real world scenarios might require way more complex topologies :)

Now that we have our sample service hosted on multiple endpoints, it is time to enable certain level of intelligent routing between the these endpoints. In order to accomplish that, we should host an instance of the Dublin’s forwarding service and configure the appropriated routing rules. However, before we get to that point, we should enable a couple of artifacts in a global configuration file like machine.config. Specifically, we should add the forwarding behavior to the behavior extensions list so that it can be accessible by the forwarding service.

   1:  ...
   2:  <behaviorextensions>
   3:   
   4:  <add name="forwardingbehavior" 
                          type="microsoft.processserver.messaging.configuration.forwardingbehaviorextensionelement,
                          microsoft.processserver.messaging, version=3.0.0.0, culture=neutral,
                          publickeytoken=31bf3856ad364e35"/>
   5:   
   6:  <add name="marshalingbehavior" 
                          type="microsoft.processserver.messaging.configuration.marshalingextensionelement, 
                          microsoft.processserver.messaging, version=3.0.0.0, culture=neutral,
                          publickeytoken=31bf3856ad364e35"/>
   7:   
   8:  </behaviorextensions> 
   9:  ...

Additionally, we should also add the filtering configuration section which details the specific syntax for expressing routing rules.

   1:  ...
   2:  <configsections>
   3:   
   4:  <sectiongroup name="system.servicemodel" type="system.servicemodel.configuration.servicemodelsectiongroup, 
                                       system.servicemodel, version=3.0.0.0, culture=neutral, 
                                       publickeytoken=b77a5c561934e089">
   5:   
   6:  <section name="filtering" type="microsoft.processserver.messaging.configuration.filteringsection, 
                         microsoft.processserver.messaging, version=3.0.0.0, culture=neutral, 
                         publickeytoken=31bf3856ad364e35"/>
   7:   
   8:  </sectiongroup>
   9:   
  10:  </configsections>
  11:   
  12:  ...

At this point we are ready to configure a new forwarding service. we can do that by simply hosting the ForwardingService service as illustrated in the following .svc file.

Now its time for to configuring the routing rules for the different service’s endpoints. When we say configure we literally mean it :). Implementing the routing rules is purely a configuration exercise that leverages the XPath message filter and filter tables among other artifacts. For our example, we will configure a couple of basics rules that determines if a transaction is over $50000.

   1:  ...
   2:  <system.serviceModel>
   3:          <services>
   4:              <service behaviorConfiguration="forwardingConfig" 
                            name="Microsoft.ProcessServer.Messaging.ForwardingService">

5: <endpoint address="RequestReply" binding="basicHttpBinding" name="reqReplyEndpoint"

contract="Microsoft.ProcessServer.Messaging.IRequestReplyDatagram"/>

   6:              </service>
   7:          </services>
   8:          <bindings>
   9:              <basicHttpBinding>
  10:                  <binding name="BasicHttpBinding_IService">
  11:                      
  12:                      <security mode="None">
  13:                          <transport clientCredentialType="None" proxyCredentialType="None" realm=""/>
  14:                          <message clientCredentialType="UserName" algorithmSuite="Default"/>
  15:                      </security>
  16:                  </binding>
  17:              </basicHttpBinding>
  18:          </bindings>
  19:          <behaviors>
  20:        
  21:              <serviceBehaviors>
  22:                  <behavior name="forwardingConfig">
  23:                      <forwardingBehavior filterTableName="contentFilterTable" filterOnHeadersOnly="false"/>
  24:            
  25:            <serviceMetadata httpGetEnabled="true"/>
  26:                  </behavior>
  27:                  <behavior name="ServiceBehavior">
  28:                    
  29:                      <serviceMetadata httpGetEnabled="true"/>
  30:                    
  31:                      <serviceDebug includeExceptionDetailInFaults="false"/>
  32:                  </behavior>
  33:              </serviceBehaviors>
  34:          </behaviors>
  35:          <client>
  36:              <endpoint address="http://localhost:49159/SampleService/Service.svc/ep1" binding="basicHttpBinding" 
                             bindingConfiguration="BasicHttpBinding_IService" 
                             contract="*" name="BasicHttpBinding_IService1"/>

37: <endpoint address="http://localhost:49159/SampleService/Service.svc/ep2" binding="basicHttpBinding"

bindingConfiguration="BasicHttpBinding_IService"

contract="*" name="BasicHttpBinding_IService2"/>

  38:          </client>
  39:          <!--FILTERING SECTION-->
  40:          <filtering>
  41:              <filters>
  42:                  <filter name="transactionFilter1" filterType="XPath" 
                               filterData="boolean(//*[local-name()= 'Amount']/text() &gt; 50000)"/>
  43:                  <filter name="transactionFilter2" filterType="XPath" 
                               filterData="boolean(//*[local-name()= 'Amount']/text() &lt; 50000)"/>
  44:              </filters>
  45:              <filterTables>
  46:                  <table name="contentFilterTable">
  47:                      <filters>
  48:                          <add filterName="transactionFilter1" mappedValue="BasicHttpBinding_IService1"/>
  49:                          <add filterName="transactionFilter2" mappedValue="BasicHttpBinding_IService2"/>
  50:                      </filters>
  51:                  </table>
  52:              </filterTables>
  53:          </filtering>
  54:      </system.serviceModel>
  55:  ...

Notice that the filter table "contentFilterTable" in line 46 associates specific filters (lines 42-43) with client's (lines 36-37) configured to forward the message to a service endpoint. In our case, we have a couple of mutually exclusive rules which determine that one endpoint will process the transactions larger than $50000 while the other will process the rest of the transactions.

With this simple configuration we leverage Dublin’s forwarding service to distribute messages across different service’s endpoints based on XPath Boolean expressions. It is important to notice that the forwarding service can leverage any WCF message filters such as Address, Endpoint, XPath, etc. Additionally, developers can create their own message filter and integrate it with the forwarding service.

.

Published Thursday, December 11, 2008 9:18 AM by gsusx

Comments

Thursday, December 11, 2008 9:47 AM by externsblogs

# Implementing content based routing using the Windows Application Server (Dublin) forwarding service

Dublin’s application server incorporates a series of runtimes services that complement the runtime behavior

# Implementing content based routing using the Windows Application Server (Dublin) forwarding service - Jesus Rodriguez's WebLog

Pingback from  Implementing content based routing using the Windows Application Server (Dublin) forwarding service - Jesus Rodriguez's WebLog

Thursday, December 11, 2008 2:32 PM by what is a windows home server | Digg hot tags

# what is a windows home server | Digg hot tags

Pingback from  what is a windows home server | Digg hot tags

Thursday, December 11, 2008 3:53 PM by Sundar

# re: Implementing content based routing using the Windows Application Server (Dublin) forwarding service

Does filtering section be defined in a perisitance store like SQL or WorlFlow Rules and hooked up to the routing service?

Thursday, December 11, 2008 5:26 PM by Jesus Rodriguez

# re: Implementing content based routing using the Windows Application Server (Dublin) forwarding service

The gwd service will work with any WCF message filter. In that sense, you can certainly define a custom filter that uses WF rules or any other mechanism. I showed an example of that in my WCF-WF MSDN WebCast last June.

Friday, December 12, 2008 12:05 AM by Technology

# Technology

Pingback from  Technology

# New and Notable 281

WCF/Azure Cloud Services/BizTalk/CSD/Dublin Both Marjan and Steve Martin point to the Beta release of BizTalk Server 2009 and the GA of RFID Mobile Meanwhile, Richard posts on what is actually in it Jesus talks about implementing Content Based routing

Friday, January 23, 2009 7:39 PM by Nicholas Allen's Indigo Blog

# Forwarding Service, Part 1

I saw that Jesus Rodriguez talked about the forwarding service that was included in the Dublin PDC preview

# Pro Information Center &raquo; Blog Archive &raquo; New and Notable 281

Pingback from  Pro Information Center  &raquo; Blog Archive   &raquo; New and Notable 281

Wednesday, March 24, 2010 1:24 PM by Melantha

# re: Implementing content based routing using the Windows Application Server (Dublin) forwarding service

Hi all. Excess on occasion is exhilarating. It prevents moderation from acquiring the deadening effect of a habit. Help me! Need information about: How to buy stocks cheap. I found only this - <a href="www.ra-waschelitz.de/.../cheap-blue-chip-stocks">cheap blue chip stocks</a>. In financing species, a first public government is not died near the restoration as a risk in the difficult important neat various fire stream, cheap stocks. Cheap stocks, types are public medieval weaponry with juvenile activities value-added to a useful industrial epitome that suggests from the fish of the experimental wood. With best wishes :rolleyes:, Melantha from Suriname.

Sunday, May 22, 2011 2:16 AM by weblogs.asp.net

# re: Implementing content based routing using the Windows Application Server (Dublin) forwarding service

Implementing content based routing using the windows application server dublin forwarding service.. Huh, really? :)

Leave a Comment

(required) 
(required) 
(optional)
(required)