How to: Route SOAP Messages Based Upon Their Content

The WSE supports routing decisions based on the content of a request message, either on content contained in the headers or on information to be found in the message body. Content-based routing enables a new path to be set by a router for a forwarded` request message. This sort of service could be used, for example, to route requests to local services based on geographical data contained in the message.

Note

Users who want to process a mustUnderstand header should use a custom policy assertion and not content-based routing. The mustUnderstand header fault checking is done before the ProcessRequestMessage method is called, so attempting to use content-based routing always results in a mustUnderstand header fault at the client. For information on adding custom filters, see How to: Create a Custom Policy Assertion that Secures SOAP Messages.

The following procedures describe how to set up a router that serves as an intermediary between the clients and the server of a Web service that checks whether a message is from a client belonging to a set of clients that has signed up for a premium service or not, and then routes the client, accordingly, to either the premium or the standard service. This is a two-step process:

  1. Create and configure a WSE router.
  2. Provide the WSE router with the logic for content-based routing.

To create and configure a WSE router

  1. In Visual Studio 2005, create an ASP.NET Web Service project.

    1. Start Visual Studio 2005.
    2. On the File menu, point to New, and then click Project.
    3. In the Project Types pane, select Visual C# Projects.
    4. In the Templates pane, select ASP.NET Web Service.
    5. In the Location box, enter the name of the Web server with a project name of https://localhost/CBRouter.
    6. Click OK.
      The CBRouter project is added to the solution. The Component Designer appears in the development environment.
    7. In Solution Explorer, right-click CBRouter, choose Add, and then click Add Class.
    8. Under Web Project Items, select the class template, in the Name box, enter CBRoutingHandler, and then click OK.
  2. Add references to the Microsoft.Web.Services3 and System.Web.Services assemblies.

    1. In Solution Explorer, right-click References, and then select Add Reference.
    2. Click the .NET tab, select Microsoft.Web.Services3.dll, and then click Select.
    3. On the .NET tab, select System.Web.Services.dll, and then click Select.
    4. Click OK.
  3. Add Imports or using directives for WSE-related namespaces.

    1. Open the CBRoutingHandler.cs file.

    2. At the top of the file, add the directives as shown in the following code example.

      Imports System
      Imports System.Configuration
      Imports System.Xml
      Imports Microsoft.Web.Services3
      Imports Microsoft.Web.Services3.Messaging
      
      using System;
      using System.Configuration;
      using System.Xml;
      using Microsoft.Web.Services3;
      using Microsoft.Web.Services3.Messaging;
      
  4. Edit the RoutingHandler class to derive from the Microsoft.Web.Services3.Messaging.SoapHttpRouter class**.** The edited code for the class should then read as shown in the following code example.

    Public Class RoutingHandler
        Inherits Microsoft.Web.Services3.Messaging.SoapHttpRouter
    
    public class RoutingHandler :
        Microsoft.Web.Services3.Messaging.SoapHttpRouter
    
  5. Edit the Web.config file of the WSE router to run for a Web application.

    1. In Solution Explorer, double-click Web.config.

    2. Include an <add> element for the <httpHandlers> section to specify the routing class.
      The following code example configures the WSE router to run for all SOAP requests received for files with an .asmx extension in this Web application.

      <configuration>
          <system.web>
              <httpHandlers>
                  <add verb="*" path="*.asmx"
                      type="CBRouter.CBRoutingHandler, CBRouter" />
              </httpHandlers>
          </system.web>
      </configuration>
      

      Note

      The type attribute of the <add> Element for <httpHandlers> section must be on one line, even though this example code contains line breaks for readability.

To provide content-based routing logic for the WSE router

  1. Add logic to the router that sends requests to the premium service if a client has subscribed; otherwise, send requests to the standard service.

    1. Create a method that overrides the ProcessRequestMessage method.

      Protected Overrides Function ProcessRequestMessage(ByVal message As SoapEnvelope) As Uri
      
      protected override Uri ProcessRequestMessage(SoapEnvelope message)
      
    2. Provide the logic for the content-based routing to the premium service.
      For example, if the premium clients put a header named Premium in the message to indicate that they subscribe to the premium service at PremiumServiceUri or a header named Standard in the message to indicate that they subscribe to the standard service at StandardServiceUri, the following code example could be used to insert a new via statement in the path of the forwarded message.

      ' Look for any Premium headers.
      Dim headersMatched As XmlNodeList = _
          message.Header.GetElementsByTagName(PremiumHeaderName, PremiumNamespaceUri)
      If (headersMatched.Count = 0) Then
          ' Defer to the WSE RoutingHandler's implementation
          Return MyBase.ProcessRequestMessage(message)
      Else
          ' Add your custom code here that adds a new via. By adding a
          ' a via element that specifies the endpoint of the premium
          ' service, the SOAP message is sent to the premium
          ' service instead of the standard service.
          Return premiumServiceUri
      End If
      
      // Look for any Premium headers.
      XmlNodeList headersMatched = message.Header.GetElementsByTagName(PremiumHeaderName, PremiumNamespaceUri);
      if (headersMatched.Count == 0)
      {
          // Defer to the WSE RoutingHandler's implementation
          return base.ProcessRequestMessage(message);
      }
      else
      {
          // Add your custom code here that adds a new via. By adding a
          // a via element that specifies the endpoint of the premium
          // service, the SOAP message is sent to the premium
          // service instead of the standard service.
          return premiumServiceUri;
      }
      

Example

The following code example is a SOAP router that routes messages based on the SOAP headers present in the message.

Imports System
Imports System.Configuration
Imports System.Xml
Imports Microsoft.Web.Services3
Imports Microsoft.Web.Services3.Messaging
Namespace QuoteRouter
    Public Class RoutingHandler
        Inherits Microsoft.Web.Services3.Messaging.SoapHttpRouter
        Shared ReadOnly PremiumNamespaceUri As String = _
            "http://schemas.contoso.com/cbr"
        Shared ReadOnly PremiumHeaderName As String = "Premium"

        ' The uri to which this routing handler will forward premium 
        ' requests to in lieu of using the default WSE RoutingHandler's
        ' implementation.
        Dim premiumServiceUri As Uri

        Public Sub RoutingHandler()
            ' Look up the premium web service's uri from the
            ' configuration file.
            Dim premiumServiceUrl As String = _
                ConfigurationSettings.AppSettings("Premium Web Service")
            If (premiumServiceUrl Is Nothing OrElse _
                premiumServiceUrl.Length = 0) Then
                Throw New ConfigurationException( _
                    "There was no ""Premium Web Service"" entry in the <appSettings> section of the router's configuration file.")
            End If

            Me.premiumServiceUri = New Uri(premiumServiceUrl)
        End Sub

        Protected Overrides Function ProcessRequestMessage(ByVal message As SoapEnvelope) As Uri
            ' Look for any Premium headers.
            Dim headersMatched As XmlNodeList = _
                message.Header.GetElementsByTagName(PremiumHeaderName, PremiumNamespaceUri)
            If (headersMatched.Count = 0) Then
                ' Defer to the WSE RoutingHandler's implementation
                Return MyBase.ProcessRequestMessage(message)
            Else
                ' Add your custom code here that adds a new via. By adding a
                ' a via element that specifies the endpoint of the premium
                ' service, the SOAP message is sent to the premium
                ' service instead of the standard service.
                Return premiumServiceUri
            End If
        End Function
    End Class
End Namespace
using System;
using System.Configuration;
using System.Xml;
using Microsoft.Web.Services3;
using Microsoft.Web.Services3.Messaging;

namespace QuoteRouter
{
    public class RoutingHandler :
        Microsoft.Web.Services3.Messaging.SoapHttpRouter
    {
        static readonly string PremiumNamespaceUri = 
            "http://schemas.contoso.com/cbr";
        static readonly string PremiumHeaderName = "Premium";

        // The uri to which this routing handler will forward premium 
        // requests to in lieu of using the default WSE RoutingHandler's
        // implementation.
        Uri premiumServiceUri;

        public RoutingHandler()
        {
            // Look up the premium web service's uri from the
            // configuration file.
            string premiumServiceUrl =
                ConfigurationSettings.AppSettings["Premium Web Service"];
            if (premiumServiceUrl == null || premiumServiceUrl.Length == 0)
            {
                throw new ConfigurationException("There was no \"Premium Web Service\" entry in the <appSettings> section of the router's configuration file.");
            }

            this.premiumServiceUri = new Uri(premiumServiceUrl);
        }
        
        protected override Uri ProcessRequestMessage(SoapEnvelope message)
        {
            // Look for any Premium headers.
            XmlNodeList headersMatched = message.Header.GetElementsByTagName(PremiumHeaderName, PremiumNamespaceUri);
            if (headersMatched.Count == 0)
            {
                // Defer to the WSE RoutingHandler's implementation
                return base.ProcessRequestMessage(message);
            }
            else
            {
                // Add your custom code here that adds a new via. By adding a
                // a via element that specifies the endpoint of the premium
                // service, the SOAP message is sent to the premium
                // service instead of the standard service.
                return premiumServiceUri;
            }
        }
    }
}

See Also

Other Resources

Routing SOAP Messages with WSE