Moving from WS-Routing to WS-Addressing Using WSE 2.0

 

Aaron Skonnard
Northface University

April 2004

Applies to:
   Web Services Enhancements 2.0 for Microsoft® .NET
   WS-Routing specification
   WS-Addressing specification

Summary: See the issues surrounding Web services routing and the need for transport-neutral addressing, specifically focusing on the move away from WS-Routing towards the new WS-Addressing specification. Core WS-Addressing concepts and implementing secure routing with Web Service Enhancements 2.0 are shown. (21 printed pages)

Contents

Introduction
Transport Neutrality
Transport Dependencies
WS-Routing Revisited
"Next Hop" Routing
Enter WS-Addressing
Endpoint References
Binding Endpoint References to Headers
WS-Addressing in WSE 2.0
Routing with WSE 2.0
Secure Routing with WSE 2.0
Where Are We?
References
Related Books

Introduction

This article addresses the issues surrounding Web services routing and the need for transport-neutral addressing, specifically focusing on the move away from WS-Routing towards the new WS-Addressing specification. In doing so, we'll cover core WS-Addressing concepts and show how to implement secure routing with Web Services Enhancements (WSE) 2.0.

Transport Neutrality

Before digging into the nuts and bolts of WS-Addressing and routing, it's important to understand one key Web services concept that has motivated the design of SOAP and various layered WS-* specifications, including WS-Addressing. The concept is that of transport neutrality.

Although most developers think of Web services as being inherently tied to HTTP, the fundamental architecture as well as the more advanced layers are designed to be transport-neutral. You can see evidence of this in the <soap:Envelope> element, which provides a framework for separating an XML payload from accompanying headers:

<soap:Envelope 
  xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Header>
    <!-- headers go here -->
  </soap:Header>
  <soap:Body>
    <!-- payload goes here -->
  </soap:Body>
</soap:Envelope>

SOAP's distinction between payload and headers makes it possible to capture application protocol information without creating dependencies on transport protocols. As long as the sender and receiver share an understanding of the XML headers placed in the SOAP message, they can exchange SOAP messages over a variety of different transports.

Transport Dependencies

Despite the focus on transport neutrality, most of today's SOAP infrastructure does not provide a mechanism for referencing endpoints and dispatching messages without the help of a transport protocol.

For example, when using SOAP over HTTP, the target URI of the HTTP request message represents the address of the SOAP endpoint. This is the only place that the address of the endpoint is referenced. Once the message arrives for processing, the SOAP infrastructure uses the HTTP SOAPAction header to determine what should happen in response to the message. Most SOAP implementations use this information to dispatch the message to a particular method (see Figure 1).

Figure 1. SOAP Address and Action

Placing this information in the transport protocol ties SOAP routing and dispatching to transport specifics and consequently places more demands on the developer. If you were to send this message over a different transport, you'd have to find a way to carry the same information in the new protocol, not to mention in a standard way. Additionally, putting the information in the transport protocol is an obstacle to messages using different transport protocols for different parts of their journeys; for example, one leg using HTTP and another using e-mail. Finally, security mechanisms applied to a SOAP message would not secure information outside the message, in the transport protocol.

It is more self-contained, reusable, and secure to carry this information in the SOAP header section. This would make it possible for SOAP infrastructure to accommodate a wider range of transports while simplifying the programming model. Ultimately, removing transport dependencies will improve overall the simplicity and flexibility of SOAP.

WS-Routing Revisited

WS-Routing was the first specification to tackle this issue. WS-Routing provided the capability to specify message routing and dispatching information in a transport-neutral way. Check out Routing SOAP Messages with Web Services Enhancements 1.0 for additional background information.

The specification defined a new element (named <r:path>) to be used in the SOAP Header block. The path element has several child elements that can be used to specify routing and dispatching information, including <r:to> and <r:action>. These elements can be used to capture the same information as before, but without any ties to a transport protocol, as illustrated in Figure 2.

Figure 2. WS-Routing path header

In addition to <r:to> and <r:action>, WS-Routing defines several optional elements designed for more sophisticated message-routing scenarios. Code Listing 1 shows the complete structure of <r:path> as defined by WS-Routing (the asterisk '*' means there can be multiple occurrences).

Code Listing 1. Structure of WS-Routing "path" Element

<s:Envelope
   xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"
>
  <s:Header>
    <!-- WS-Routing -->
    <r:path xmlns:r="http://schemas.xmlsoap.org/rp">
       <r:action />
       <r:to />
       <r:fwd>
         <r:via /> *
       </r:fwd>
       <r:rev>
         <r:via /> *
       </r:rev>
       <r:from />
       <r:id />  
       <r:relatesTo />
       <r:fault />
    </r:path>
    ...

These elements allow messages to describe their own routes. Messages can define a forward path (<r:fwd>), a reverse path for a corresponding response message (<r:rev>), as well as a way to correlate messages (<r:id> and <r:relatesTo>). Routers designed to process path information must make changes to the WS-Routing header before sending the message along to the next node in the path. For example, routers must remove the first <r:via> element and forward the message to the node identified by the next <r:via> element. This continues until the message arrives at the node identified by the <r:to> element. Routers may also build a reverse path along the way.

Although this intra-message routing capability offers some interesting possibilities, it also presents some serious security challenges. The fact that routers must modify the header complicates message signatures. The original sender cannot sign the message (including the WS-Routing headers) and send it through a WS-Routing path without breaking the original signature.

Encryption introduces a set of similar challenges with regards to routing because routers need to read, modify, and then re-encrypt the message and headers before sending it off again. Intermediaries would need the security tokens required to read, sign, and re-encrypt the messages for this to work. This is a challenge in and of itself.

You could avoid signing and encrypting the WS-Routing header, but then you're opening your system to attack. These security challenges motivated a simpler approach to SOAP-based routing.

"Next Hop" Routing

An easy way to simplify WS-Routing and mitigate the security challenges mentioned above is to avoid using the path elements altogether (<r:fwd> and <r:rev>). Avoiding these elements removes the need for intermediaries to modify the message.

Some may think that losing intra-message path information is a big sacrifice, but others will argue that it's not the right way to implement routing anyway. The basis of their argument is that senders shouldn't have to know the architectural details required to build a message path. Instead, senders should only have to know about a single endpoint, which can take care of additional routing needs behind closed doors. You can think of this as "next hop" routing.

"Next hop" routing is essentially how TCP/IP works. A TCP/IP message contains information about where the message came from and where it's going, but it doesn't contain details on how the message gets there. As a TCP/IP message travels through a network, each node inspects the TCP/IP header to see where it's headed and then it sends the message to the next TCP/IP node closer to the destination. This continues until the node reaches its destination.

This explains some of the reasoning behind the design of WS-Addressing, which offers a secure "next hop" routing mechanism.

Enter WS-Addressing

As an improvement to WS-Routing, WS-Addressing provides a transport-neutral mechanism for addressing Web services. WS-Addressing formalizes the simplification of WS-Routing described above and adds a few additional features that we'll cover below.

WS-Addressing officially drops the WS-Routing elements related to message paths (including <r:path>, <r:fwd> and <r:rev>) and assumes users will rely on the "next hop" approach for routing needs. Most of the elements defined by WS-Addressing are semantically equivalent to those originally defined in WS-Routing.

Table 1 describes the WS-Addressing message information headers and shows how they map to their WS-Routing predecessors. All of these elements are associated with the WS-Addressing namespace identified by the following URI: http://schemas.xmlsoap.org/ws/2003/03/addressing.

Table 1. WS-Addressing Message Information Headers

Name WS-Routing Predecessor Type Description
wsa:MessageID r:path/r:id xsd:anyURI A URI that uniquely identifies this message in time and space.
wsa:RelatesTo r:path/r:relatesTo xsd:anyURI A pair of values that indicate how this message relates to another message. The type of the relationship is identified by a QName. The related message is identified by a URI that corresponds to the related message's MessageID value. A reply message MUST contain a wsa:RelatesTo header consisting of wsa:Reply and the message id property of the request message.
wsa:To r:path/r:to xsd:anyURI The address of the intended receiver of this message.
wsa:Action r:path/r:action xsd:anyURI An identifier that uniquely (and opaquely) identifies the semantics implied by this message.
wsa:From r:path/r:from endpoint-ref Reference of the endpoint where the message originated from.
wsa:ReplyTo N/A endpoint-ref An endpoint reference that identifies the intended receiver for replies to this message. If a reply is expected, a message MUST contain a wsa:ReplyTo header. The sender MUST use the contents of the wsa:ReplyTo header to formulate the reply message. If the wsa:ReplyTo header is absent, the contents of the wsa:From header may be used to formulate a message to the source. This property MAY be absent if the message has no meaningful reply. If this property is present, the wsa:MessageID header is REQUIRED.
wsa:FaultTo N/A endpoint-ref An endpoint reference that identifies the intended receiver for faults related to this message. When formulating a fault message, the sender must use the contents of this reference to formulate the fault message. If this reference is absent, the sender may use the contents of wsa:ReplyTo to formulate the fault message. If this reference and wsa:ReplyTo are both absent, the sender may use the contents of wsa:From to formulate the fault message. If this property is present, the [message id] property is REQUIRED.

You specify the destination of the message with <wsa:To>, the action with <wsa:Action>, and you give the message a unique ID with <wsa:MessageID>. If it's a reply message, you indicate its relationship to the request message using the <wsa:RelatesTo> header and its RelationshipType attribute.

Since WS-Addressing moves away from message paths, it doesn't define another container element like <r:path> (see Code Listing 1). Instead, WS-Addressing elements are simply placed as immediate children of <soap:Header>. Figure 3 illustrates how to map WS-Routing information to WS-Addressing.

Figure 3. Mapping WS-Routing to WS-Addressing

Only <wsa:To> and <wsa:Action> are required in request messages when using WS-Addressing (the remaining elements are optional). SOAP infrastructure that supports WS-Addressing should dispatch messages based on these two values. You can also implement a simple "next hop" routing mechanism using these two values. You can treat <wsa:To> as a logical address and provide a simple translation to a physical address at an intermediate routing node (more on this later).

In addition to what carries over from WS-Routing, WS-Addressing also introduces a new mechanism for referencing endpoints in a standard, semantically rich way. This makes it possible to transmit an endpoint reference in a message (think pass by reference), indicating to the receiver where to send future messages. WS-Addressing introduces a new schema type for this purpose called endpoint reference.

Endpoint References

In WS-Routing, <r:from> was simply a URI. This made it possible to pass the address of the sender in the message. Receivers could then send response messages back to the sender's address. This provided a limited mechanism for passing endpoint references in messages. However, in order to use the service referenced by <r:from>, the receiver had to know various service details ahead of time (such as the service contract and policies).

In WS-Addressing, the <wsa:From> element is of type endpoint reference. An endpoint reference makes it possible to pass additional endpoint metadata along with the address. Ideally, endpoint references will contain enough information for consumers to automatically negotiate interactions.

In order to accomplish this, endpoint references must contain the address along with additional properties that allow discovery of contract details and policies. These additional properties may include the service name, port name, port type, and WS-Policy statements that describe the requirements, capabilities, and preferences of the service. A reference should also be able to hold as many application-specific properties as needed.

The WS-Addressing specification defines a complex type definition that provides a structure for endpoint reference information. Its name is wsa:EndpointReferenceType (see Code Listing 2).

Code Listing 2: WS-Addressing XML Schema Definition

... 
<xs:complexType name="EndpointReferenceType">
  <xs:sequence>
    <xs:element name="Address" type="wsa:AttributedURI" /> 
    <xs:element name="ReferenceProperties" 
      type="wsa:ReferencePropertiesType" minOccurs="0" /> 
    <xs:element name="PortType" type="wsa:AttributedQName" 
      minOccurs="0" /> 
    <xs:element name="ServiceName" type="wsa:ServiceNameType"   
      minOccurs="0" /> 
    <xs:any namespace="##other" processContents="lax" 
      minOccurs="0" maxOccurs="unbounded"/>
  </xs:sequence>
  <xs:anyAttribute namespace="##other" processContents="lax" /> 
</xs:complexType>

<xs:element name="EndpointReference" 
  type="wsa:EndpointReferenceType"/> 
...

<wsa:Address> is the only required element in wsa:EndpointReferenceType. The <wsa:ReferenceProperties> element is basically a container for additional custom properties (it holds a sequence of xsd:any elements). The <wsa:ServiceName> element comes with a PortName attribute even though it's not shown in Code Listing 2. The xsd:any sequence that comes after <wsa:ServiceName> is an extensibility point where additional elements may be placed. This is where you place policy elements. See Table 2 for complete descriptions of each construct.

Table 2: EndpointReferenceType Elements

Name Description
Address An address URI that identifies the endpoint. This may be a network address or a logical address.
ReferenceProperties A reference may contain a number of individual properties that are required to identify the entity or resource being conveyed.
PortType The QName of the primary portType of the endpoint being conveyed.
ServiceName This is the QName identifying the WSDL service element that contains the definition of the endpoint being conveyed. The service name provides a link to a full description of the service endpoint. An optional non-qualified name identifies the specific port in the service that corresponds to the endpoint.
[policy] A variable number of XML policy elements, as detailed in WS-Policy, that describe the behavior, requirements, and capabilities of the endpoint. Policies may be included in an endpoint to facilitate easier processing by the consuming application, or because the policy was dynamically generated.

The WS-Addressing schema also defines an element named <wsa:EndpointReference> of type wsa:EndpointReferenceType (see Code Listing 2). The following shows a complete <EndpointReference> sample:

<wsa:EndpointReference xmlns:c="http://example.org/claims"
  xmlns:p="http://schemas.xmlsoap.org/ws/2002/12/policy"
>
  <wsa:Address>http://claimserver/ins/p.asmx</wsa:Address>
  <wsa:ReferenceProperties>
    <c:PatientProfile>123456</c:PatientProfile>
    <c:CarrierID>987654</c:CarrierID>
  </wsa:ReferenceProperties>
  <wsa:PortType>c:ClaimsPortType</wsa:PortType>
  <wsa:ServiceName PortName="c:ClaimsSoapPort">c:ClaimsService
 </wsa:ServiceName>
  <p:Policy>
    ... <!-- policy statement omitted for brevity --> 
  </p:Policy>
</wsa:EndpointReference>

You don't have to use the <wsa:EndpointReference> element in all situations. It's provided in the schema as a convenience. You can define new elements of type wsa:EndpointReferenceType. This is precisely how the last three message information headers shown in Table 1 (<wsa:From>, <wsa:ReplyTo>, and <wsa:FaultTo>) are defined.

As before, <wsa:From> is a reference to the endpoint that originated the message. Receivers should send response messages to this endpoint when <wsa:ReplyTo> is absent. It's important to note that various networking technologies such as NAT, DHCP, and firewalls make it difficult for environments to assign a meaningful address to a sending node. WS-Addressing defines a well-known URI for identifying these "anonymous" endpoints: http://schemas.xmlsoap.org/ws/2003/03/addressing/role/anonymous. When applications use this value, they must provide some other out-of-bounds mechanism for relaying response messages.

The <wsa:ReplyTo> element is a reference to the endpoint where reply messages should be sent while the <wsa:FaultTo> element is a reference to an endpoint where faults related to the message should be sent. This means that each of these elements can contain a structure like the one shown above.

Code Listing 3 shows an example that uses some of the message headers of type wsa:EndpointReferenceType.

Code Listing 3: Complete WS-Addressing Example

<s:Envelope xmlns:s="..." xmlns:wsa="...">
  <s:Header>
    <wsa:Action>http://skonnard.com/SubmitClaim</wsa:Action>
    <wsa:To>http://skonnard.com/Claims/Submit.asmx</wsa:To>
    <wsa:From>
      <wsa:Address>http://skonnard.com/main/sub.asmx</wsa:Address>
      <wsa:ReferenceProperties>
        <c:PatientProfile>123456</c:PatientProfile>
        <c:CarrierID>987654</c:CarrierID>
      </wsa:ReferenceProperties>
    </wsa:From>
    <wsa:ReplyTo>
      <wsa:Address>http://skonnard.com/resp/resp.asmx</wsa:Address>
      <wsa:ReferenceProperties>
        <c:PatientProfile>123456</c:PatientProfile>
        <c:CarrierID>987654</c:CarrierID>
      </wsa:ReferenceProperties>
    </wsa:ReplyTo>
    <wsa:FaultTo>
      <wsa:Address>http://skonnard.com/fault/err.asmx</wsa:Address>
      <wsa:ReferenceProperties>
        <c:PatientProfile>123456</c:PatientProfile>
        <c:CarrierID>987654</c:CarrierID>
      </wsa:ReferenceProperties>
    </wsa:FaultTo>
  </s:Header>
  <s:Body xmlns:c="http://example.org/claims">
    <c:SubmitClaim> ... </c:SubmitClaim>
  </s:Body>
</s:Envelope>

As you can see, endpoint references may contain much more than simply an address. The additional information makes it possible for nodes to negotiate interactions with other endpoints in rich ways.

Binding Endpoint References to Headers

When an application decides to use an endpoint described by an endpoint reference, it must use a binding to map the information from the endpoint reference into the appropriate message headers.

The WS-Addressing specification only defines a single binding for SOAP messages. The SOAP binding states that the address property is mapped to the <wsa:To> header, and each reference property becomes an independent header block as illustrated in Figure 4.

Figure 4. Endpoint Reference SOAP Binding

WS-Addressing in WSE 2.0

One of the most fundamental changes in WSE 2.0 is that it drops support for WS-Routing and adds support for WS-Addressing. WSE 2.0 provides various new classes for WS-Addressing in the Microsoft.Web.Services.Addressing namespace. The entire message API has been reworked around endpoint references instead of URIs. WSE 2.0 introduces a new class named EndpointReference that replaces System.Uri throughout the WSE 2.0 API.

For example, the SoapSender and SoapReceiver classes now deal with EndpointReference objects directly. The following code snippet illustrates how to use an EndpointReference object with the SoapSender class in a simple TCP-based chat application:

...
SoapEnvelope env = new SoapEnvelope();
env.Context.Addressing.Action = String.Format("urn:chat:message");
EndpointReference epr = 
  new EndpointReference("soap.tcp://askonnard:123/aaron"));
env.Context.Addressing.ReplyTo = new ReplyTo(epr);
env.CreateBody(); // must create body before setting it
env.Body.InnerXml = String.Format(
  "<x:message xmlns:x='urn:chat'><user>{0}</user><msg>{1}</msg>
</x:message>", user, msg);
...
EndpointReference epr = new EndpointReference(
   new Uri("soap.tcp://askonnard:456/monica"));
SoapSender ss = new SoapSender(epr);
ss.Send(env);
...

Whenever you send a message with WSE 2.0, it automatically adds the required WS-Addressing message information headers. For example, the previous code snippet will produce the following SOAP message:

<soap:Envelope  
  xmlns:wsa="http://schemas.xmlsoap.org/ws/2003/03/addressing"   
  xmlns:wsse="http://schemas.xmlsoap.org/ws/2003/06/secext"   
  xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Header>
    <wsa:Action>urn:chat:message</wsa:Action>
    <wsa:ReplyTo>
      <wsa:Address>soap.tcp://askonnard:123/aaron</wsa:Address>
    </wsa:ReplyTo>
    <wsa:MessageID>uuid:59bc1ebb-40aa-4508-9a69-5b148d04d697
    </wsa:MessageID>
    <wsa:To>soap.tcp://askonnard:456/monica</wsa:To>
    ...
  </soap:Header>
  <soap:Body>
    <x:message xmlns:x="urn:chat">
      <user>aaron</user>
      <msg>hi</msg>
    </x:message>
  </soap:Body>
</soap:Envelope>

In the previous example, the EndpointReference objects only contain an address. You can populate the EndPointReference with additional properties as illustrated here:

...
EndpointReference epr = new EndpointReference(
   new Uri("soap.tcp://askonnard:456/monica"));
epr.ServiceName = new ServiceName(
   new XmlQualifiedName("WseChat", "urn:chat"));
epr.ServiceName.PortName = "ChatPort";
epr.PortType = new PortType(
   new XmlQualifiedName("WseChatSoapPort", "urn:chat"));

// set some custom reference properties...
epr.ReferenceProperties = new ReferenceProperties();
epr.ReferenceProperties.LoadXml(GetReferenceProperties());

env.Context.Addressing.ReplyTo = new ReplyTo(epr);
...

When you send this SoapEnvelope, the WSE infrastructure produces the following SOAP message:

<soap:Envelope 
 xmlns:wsa="http://schemas.xmlsoap.org/ws/2003/03/addressing"   
 xmlns:wsse="http://schemas.xmlsoap.org/ws/2003/06/secext" 
 xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Header>
    <wsa:Action>urn:chat:message</wsa:Action>
    <wsa:MessageID>uuid:7e44dd92-ec1a-4b75-aa5d-8744698a5d39
    </wsa:MessageID>
    <wsa:ReplyTo>
      <wsa:Address>soap.tcp://localhost:123/aaron</wsa:Address>
      <wsa:ReferenceProperties>
        <x:MyHeader1 xmlns:x="urn:example">Foo</x:MyHeader1>
        <x:MyHeader2 xmlns:x="urn:example">Bar</x:MyHeader2>
      </wsa:ReferenceProperties>
      <wsa:PortType xmlns:prefix0="urn:chat"
      >prefix0:WseChatSoapPort</wsa:PortType>
      <wsa:ServiceName wsa:PortName="ChatPort" 
       xmlns:prefix1="urn:chat">prefix1:WseChat</wsa:ServiceName>
    </wsa:ReplyTo>
    <wsa:To>soap.tcp://askonnard:456/monica</wsa:To>
    ...
  </soap:Header>
  <soap:Body>
    <x:message xmlns:x="urn:chat">
      <user>aaron</user>
      <msg>hi</msg>
    </x:message>
  </soap:Body>
</soap:Envelope>

Then, inside a SoapReceiver implementation you can use the <wsa:ReplyTo> reference as the target for response messages:

public class ChatReceiver : SoapReceiver
{
   protected override void Receive(SoapEnvelope e)
   {
      // extract message fields from SOAP envelope
      SoapSender ss = new SoapSender(e.Context.Addressing.ReplyTo);
      ... // send response message

   }
}

The WSE infrastructure will automatically apply the SOAP endpoint reference binding and map the <wsa:ReplyTo> information to the appropriate message headers. In this case, a response message looks like this:

<soap:Envelope 
 xmlns:wsa="http://schemas.xmlsoap.org/ws/2003/03/addressing"   
 xmlns:wsse="http://schemas.xmlsoap.org/ws/2003/06/secext" 
 xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Header>
    <wsa:Action>urn:chat:message</wsa:Action>
    <wsa:MessageID>uuid:7e44dd92-ec1a-4b75-aa5d-8744698a5d40
    </wsa:MessageID>
    <x:MyHeader1 xmlns:x="urn:example">Foo</x:MyHeader1>
    <x:MyHeader2 xmlns:x="urn:example">Bar</x:MyHeader2>
    <wsa:To>soap.tcp://askonnard:123/aaron</wsa:To>
    <wsa:RelatesTo RelationshipType="wsa:Reply">
      7e44dd92-ec1a-4b75-aa5d-8744698a5d39
    </wsa:RelatesTo>
    ...
  </soap:Header>
  <soap:Body>
    <x:message xmlns:x="urn:chat">
      <user>aaron</user>
      <msg>hi</msg>
    </x:message>
  </soap:Body>
</soap:Envelope>

Notice that the <wsa:ReplyTo> address was mapped to the <wsa:To> header and the custom reference properties became independent header blocks (<x:MyHeader1> and <x:MyHeader2>).

Routing with WSE 2.0

There are a few ways to implement "next hop" routing with WS-Addressing and WSE 2.0. One way is to provide a simple translation of the <wsa:To> address to another address. WS-Referral provides a mechanism for this type of address translation.

The following WS-Referral statement indicates that messages targeting http://skonnard.com/Claims/Submit.asmx should be routed to http://claimserver/ins/sub.asmx for processing:

<!-- referralCache.config -->
<r:referrals 
  xmlns:r="http://schemas.xmlsoap.org/ws/2001/10/referral">
  <r:ref>
    <r:for>         
      <r:exact>http://skonnard.com/Claims/Submit.asmx</r:exact>
    </r:for>
    <r:if />
    <r:go>
      <r:via>http://claimserver/ins/sub.asmx</r:via>
    </r:go>
  </r:ref>
</r:referrals>

WSE 2.0 provides support for referral-based routing through the Microsoft.Web.Services.Messaging.SoapHttpRouter handler. You can configure an endpoint to use this handler along with a referral cache by adding the following sections to your web.config file (note: code line breaks have been added for readability):

<configuration>
  <configSections>
    <section name="microsoft.web.services" 
      type="Microsoft.Web.Services.Configuration.WebServicesConfiguration, 
      Microsoft.Web.Services, Version=2.0.0.0, Culture=neutral, 
      PublicKeyToken=31bf3856ad364e35" />
  </configSections>
  <system.web>
    <webServices>
      <soapExtensionTypes>
        <add type="Microsoft.Web.Services.WebServicesExtension, 
      Microsoft.Web.Services, Version=2.0.0.0, Culture=neutral, 
      PublicKeyToken=31bf3856ad364e35" priority="1" group="0" />
      </soapExtensionTypes>
    </webServices>
    <httpHandlers>
      <add type="Microsoft.Web.Services.Messaging.SoapHttpRouter, 
      Microsoft.Web.Services, Version=2.0.0.0, Culture=neutral, 
      PublicKeyToken=31bf3856ad364e35" path="*.ashx" verb="*" />
    </httpHandlers>
  </system.web>
  <microsoft.web.services>
    <referral>
      <cache name="referralCache.config" />
    </referral>
  </microsoft.web.services>
</configuration>              

When you send a message to an .ashx endpoint in this virtual directory, the SoapHttpRouter will inspect the WS-Referral cache to determine the address of the next hop. Messages with a <wsa:To> address of http://localhost/endpoints/echo.ashx will be automatically routed to http://claimserver/ins/sub.asmx as directed by the WS-Referral statement:

Another way to implement "next hop" routing is to write a custom router class that inspects the content of the message to determine routing decisions. This is referred to as content-based routing. See the WSE 2.0 documentation for more details.

Secure Routing with WSE 2.0

Now that WSE 2.0 supports WS-Addressing, you can safely sign and encrypt SOAP messages without facing the challenges introduced by WS-Routing. This is due to the fact that WS-Addressing headers are immutable—they are not for modification by intermediaries. Hence, you can sign and encrypt your messages, including the WS-Addressing headers, to achieve the appropriate level of security for your needs.

The following example illustrates how to sign the entire SOAP message using a WSE 2.0 proxy class:

...
MyClaimsService e = new MyClaimsService();
e.RequestSoapContext.Security.Tokens.Add(GetSecurityToken());
e.RequestSoapContext.Security.Elements.Add(
  new Signature(tok));
e.Submit(claim);
...

The signed message produced by this code can be routed using the techniques described in the previous section, but now in a secure fashion. It is strongly recommended that you sign (and when necessary, encrypt) the WS-Addressing headers that may compromise your system's security.

Where Are We?

In this article we've discussed the need for WS-Addressing and the reasons behind the move away from WS-Routing. We've discussed how WS-Addressing allows messages to be securely routed using standard WS-Security techniques. WSE 2.0 provides full support for WS-Addressing and "next hop" routing.

References

Web Services Addressing (WS-Addressing) specification

Expanding the Communications Capabilities of Web Services with WS-Addressing

SOAP Version 1.2 Part 1: Messaging Framework

Related Books

Web Services Enhancements: Understanding the WSE for .NET Enterprise Applications

Understanding Web Services Specifications and the WSE

Show: