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 input filter 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 Creating Custom Filters with WSE.
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:
- Create and configure a WSE router.
- Provide the WSE router with the logic for content-based routing.
To create and configure a WSE router
In Visual Studio .NET 2003, create an ASP.NET Web Service project.
- Start Visual Studio .NET 2003.
- On the File menu, point to New, and then click Project.
- In the Project Types pane, select Visual C# Projects.
- In the Templates pane, select ASP.NET Web Service.
- In the Location box, enter the name of the Web server with a project name of https://localhost/CBRouter.
- Click OK.
The CBRouter project is added to the solution. The Component Designer appears in the development environment. - In Solution Explorer, right-click CBRouter, choose Add, and then click AddClass.
- Under Web Project Items, select the class template, in the Name box, enter CBRoutingHandler, and then click OK.
Add references to the Microsoft.Web.Services2 and System.Web.Services assemblies.
- In Solution Explorer, right-click References, and then select Add Reference.
- Click the .NET tab, select Microsoft.Web.Services2.dll, and then click Select.
- On the .NET tab, select System.Web.Services.dll, and then click Select.
- Click OK.
Add Imports or using directives for WSE-related namespaces.
Open the CBRoutingHandler.cs file.
At the top of the file, add the directives as shown in the following code example.
Imports System.Configuration Imports System.Xml Imports Microsoft.Web.Services2 Imports Microsoft.Web.Services2.Messaging
using System.Configuration; using System.Xml; using Microsoft.Web.Services2; using Microsoft.Web.Services2.Messaging;
Edit the RoutingHandler class to derive from the Microsoft.Web.Services2.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.Services2.Messaging.SoapHttpRouter
public class RoutingHandler : Microsoft.Web.Services2.Messaging.SoapHttpRouter
Edit the Web.config file of the WSE router to run for a Web application.
In Solution Explorer, double-click Web.config.
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> (WSE for Microsoft .NET) 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
Add logic to the router that sends requests to the premium service if a client has subscribed; otherwise, send requests to the standard service.
Create a method that overrides the ProcessRequestMessage method.
Protected Overrides Function ProcessRequestMessage(message As _ SoapEnvelope) As Uri End Sub 'ProcessRequestMessage
protected override Uri ProcessRequestMessage(SoapEnvelope message)
Provide the logic for the content-based routing to the premium service.
For example, if the premium clients put a header namedPremium
in the message to indicate that they subscribe to the premium service atPremiumServiceUri
or a header namedStandard
in the message to indicate that they subscribe to the standard service atStandardServiceUri
, 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 a new via and send it off to the premium service ' by adding the new via in front. 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 a new via and send it off to the premium service // by adding the new via in front. 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.Services2
Imports Microsoft.Web.Services2.Messaging
Namespace QuoteRouter
Public Class RoutingHandler
Inherits Microsoft.Web.Services2.Messaging.SoapHttpRouter
Private Shared PremiumNamespaceUri As String = _
"http://schemas.contoso.com/cbr"
Private Shared 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.
Private premiumServiceUri As Uri
' Default constructor for this class.
Public Sub New()
' 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 'New
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 a new via and send it off to the premium service by
' adding the new via in front.
Return premiumServiceUri
End If
End Function 'ProcessRequestMessage
End Class 'RoutingHandler
End Namespace 'QuoteRouter
using System;
using System.Configuration;
using System.Xml;
using Microsoft.Web.Services2;
using Microsoft.Web.Services2.Messaging;
namespace QuoteRouter
{
public class RoutingHandler :
Microsoft.Web.Services2.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 a new via and send it off to the premium service by
// adding the new via in front.
return premiumServiceUri;
}
}
}
}