Implementing Customized Message Routing Using WSE


In addition to backing WS-Addressing and WS-ReliableMessaging, Microsoft also initially floated a pair of Web service messaging specifications, WS-Routing and WS-Referral, as part of their initial vision of the overall Web services architecture. The likelihood of these two specifications becoming Web service standards seems to be in doubt as no one besides Microsoft has stepped up to support them. Also, much of the functionality described in WS-Routing is now being provided by WS-Addressing, which has the benefit of a much broader base of support.

WSE version 1.0 supported both WS-Routing and WS-Referral, and these functionalities have been carried forward in WSE 2.0. However, since WSE 2.0 also supports WS-Addressing, it is unclear whether this support will continue. As this book goes to press, the WSE team is deciding whether or not to remove support for WS-Routing and most of WS-Referral that was included in WSE 1.0 from the final release of the 2.0 version, so don t be surprised to find changes in these messaging functionalities in the final version of the product. Since the pre-Beta version that I am working from still supports WS-Routing and WS-Referral, I will discuss these specifications and their WSE implementation because if you are looking to implement a decision-based message routing topology, WSE likely provides the best implementation for message routing without having to write it all from scratch. Remember, however, that this type of routing topology will prove useful only between endpoints that implement WSE.

The WS-Routing Model

Rather than the endpoint-based mechanism of WS-Addressing, WS-Routing defines a routing model based on a message path . In this model, when a Web service creates a new message to be sent using a WS-Routing “based topology, the message has a path element block in the message header that contains all of the information required to route messages. The initial sender and ultimate receiver in a routing topology are represented by the from and to elements, respectively. The following example shows a message created by an endpoint named Tom and sent directly to an endpoint named Fred:

 <soap:Envelope 
xmlns:soap = "http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<m:path xmlns:m="http://schemas.xmlsoap.org/rp/">
<m:action>http://example.com/routing/dosomething</m:action>
<m:to>soap://fred.example.com</m:to>
<m:fwd>
</m:fwd>
<m:rev>
</m:rev>
<m:from>soap://tom.example.com</m:from>
<m:id>uuid:84b9f5d0-33fb-4a81-b02b-5b760641c1d6</m:id>
</m:path>

</soap:Header>
<soap:Body>

</soap:Body>
</soap:Envelope>

As you can see in this example, the required action element is analogous to the SOAPAction field in the HTTP header and is used to specify a URI that represents the intended action for the SOAP message. Of course, the from and to elements show that this message was sent from Tom to Fred. The id element specifies a GUID to uniquely reference the message. The to , from , action , and id elements are created by the initial sender of the message and are not modified by any other intermediary endpoints along the message path. The other two elements (which in this example are empty) are fwd and rev , which represent the forward and reverse message paths.

When sending messages along a complex message path, you can specify both the forward path that the message should take to the ultimate receiver and the reverse path that the response message should take back to the initial receiver. In addition, SOAP routers along the message path modify the forward and reverse message paths as needed by the routing topology. The following example assumes that when a Web service router, named Bettie, forwards the message on to Fred, a new via element is created in the reverse path so that the message will return via Bettie:

 <soap:Envelope 
xmlns:soap = "http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<m:path xmlns:m="http://schemas.xmlsoap.org/rp/">
<m:action>http://example.com/routing/dosomething</m:action>
<m:to>soap://fred.example.com</m:to>
<m:fwd>
</m:fwd>
<m:rev>
<m:via>soap://bettie.example.com</m:via>
</m:rev>
<m:from>soap://tom.example.com</m:from>
<m:id>uuid:84b9f5d0-33fb-4a81-b02b-5b760641c1d6</m:id>
</m:path>

</soap:Header>
<soap:Body>

</soap:Body>
</soap:Envelope>

Also, note in this example that Bettie removed the topmost via element in the forward path and added it to the reverse path before resending the message.

In the preceding example, you might have noticed that all of the URI values in the to , from , and via elements are prefixed with soap rather than http . This is because WS-Routing introduces a new URI scheme to use when addressing Web services that are being used as SOAP routers and that are implementing WS-Routing. This scheme prefixes the URI in the routing path block with soap , which is used regardless of the underlying transport. Of course, this addressing mechanism is applicable only to WS-Routing and does not extend to any other reliable messaging specifications.

In WS-Routing, any intermediaries that move a message along the message path are specified using the via element, wherein the order of the via elements in the message s fwd element indicates the order of the intermediaries. If a message does not have a to element, the last via element denotes the ultimate destination of the message.

The complete forward message path can be created by the initial sender of a WS-Routing message, or it can be constructed and modified by the various SOAP routers as the message moves along the message path. In fact, in many cases the exact message path isn t known to a sender or routing endpoints dynamically modify the message path based on the contents of the message, and there s no reason why the service that the sender thinks is the ultimate receiver can t continue to send the message along paths unknown to the sender.

After a SOAP router validates the routing information for the incoming message, the first change that the router must make to the message header is to remove the topmost via element that contains its own URI. A Web service can add more via elements when there is a need to forward the message to additional Web services. It can also add a via element that represents a recommended return path for the response message as the topmost via element in the reverse path described by the rev element. After this, the service must send the message on to the URI listed in the topmost via element in the forward path or to the URI listed in the to element if no more via elements exist in the forward path.

The WS-Referral Model

WS-Routing describes a mechanism for a Web service acting as a SOAP router to modify via elements in the message routing header for the purpose of providing dynamic message routing capabilities. The question that WS-Routing doesn t answer, or any other existing specification for that matter, is how individual SOAP routers negotiate these message paths and how routing topologies might be constructed. WS-Referral describes a mechanism by which a Web service examines the message path for endpoints that match a set of referrals the service knows about. When a match is found, the service can change the message path to send the message to the preferred endpoint instead. The set of referrals that a SOAP router needs to know about can be maintained locally, although WS-Referral does specify how to do this. WS-Referral also enables a SOAP router to query for referral statements at other routers as well as to request that a router accept a new referral statement.

WS-Referral clearly builds upon WS-Routing, but the two specifications are designed to be orthogonal, and WS-Referral can be implemented with any scheme that defines a SOAP actor or endpoint. The end result of WS-Referral is that it enables a routing topology to dynamically route messages more easily to support advanced routing behaviors such as failover, load balancing, progressive path discovery, and outsourcing of service hosting. Perhaps the primary benefit of WS-Referral is the ability to separate the external endpoint for a Web service from the actual services that perform the work, thus insulating the client from any knowledge of the back-end architecture of the routing topology and providing a fixed address that s independent of any activity at the back end.

Referral Statement

At the core of the WS-Referral specification is the notion of a referral statement. Unlike the routing header, which is contained in the SOAP message being routed, the referral statement is maintained locally at the SOAP router, where it s used to provide the necessary logic for conditional message routing. The following referral statement present on the SOAP router named Tom dictates that if a message is received that s intended for a SOAP router named Fred, it should first be forwarded to a SOAP router named Bettie on its way to Fred.

 <r:ref xmlns:r="http://schemas.xmlsoap.org/ws/2001/10/referral"> 
<r:for>
<r:exact>soap://fred.example.com</r:exact>
</r:for>
<r:if/>
<r:go>
<r:via>soap://bettie.example.com</r:via>
</r:go>
<r:refId>uuid:fa469956-0057-4e77-962a-81c5e292f2ae </r:refId>
</r:ref>

When Tom processes an incoming message in which the value of one of the via elements or the to element is equal to soap://fred.example.com , the service adds a via element equal to soap://bettie.example.com to the forward message path in the header and forwards the message to Bettie. When Bettie receives the message, that service will continue to follow the routing path in the header and send the message on to Fred. As long as Tom persists this referral statement, all messages received by Tom on their way to Fred will be forwarded through Bettie.

The way that a SOAP router uses a referral statement is that when a message is received, the Web service checks the referral statements that it knows about for a match between a URI specified in the for element of the referral statement and the to element or any via elements in the forward message path in the routing header. When a match is found, the logic in the if element is checked. If both are satisfied, the message is forwarded to one of the addresses specified in the go statement. In addition, two SOAP endpoints can communicate to negotiate new referrals through a process of referral querying and registration.

Referral Query

Rather than rely on a static message routing topology in which referrals never change or must be updated manually at a machine, WS-Referral specifies a mechanism through which individual SOAP routers can communicate to coordinate referral information and better route messages. The first part of this mechanism is a referral query, which is a two-way messaging exchange by which one router queries for referral statements that are registered at a second SOAP router. If Web service Fred queries Tom for any referrals relating to messages headed for Bettie, they might look like the following request message:

 <soap:Envelope xmlns:soap="http://www.w3.org/2001/09/soap-envelope"> 
<soap:Header>
<m:path xmlns:m="http://schemas.xmlsoap.org/rp/">
<m:action>
http://schemas.xmlsoap.org/ws/2001/10/referral#query
</m:action>
<m:to>soap://tom.example.com</m:to>
<m:rev>
<m:via/>
</m:rev>
<m:id>uuid:e5e8d792-abe7-4476-91d0-856fbdf4a958</m:id>
</m:path>

</soap:Header>
<soap:Body>
<r:query xmlns:r="http://schemas.xmlsoap.org/ws/2001/10/referral">
<r:for>
<r:prefix>soap://bettie.example.com</r:prefix>
</r:for>
</r:query>
</soap:Body>
</soap:Envelope>

In this example, Fred uses the for child of the query element in the message body to ask Tom whether any referral statements for handling messages are currently on the way to Bettie.

In a two-way exchange, each request must have a response. Upon receiving the previous request, Tom checks the referrals in the referral cache for any referrals that match the value of the for element. If any referrals match, they are returned in the query response message. If no matching referrals exist, an empty response is returned. The following is an example referral query response to the previous message:

 <soap:Envelope xmlns:soap="http://www.w3.org/2001/09/soap-envelope"> 
<soap:Header>
<m:path xmlns:m="http://schemas.xmlsoap.org/rp/">
<m:action>
http://schemas.xmlsoap.org/ws/2001/10/referral#queryResponse
</m:action>
<m:to>soap://Fred.example.com</m:to>
<m:id>uuid:cf014249-0e2a-4f8b-9002-13a7de916be0</m:id>
<m:relatesTo>uuid:e5e8d792-abe7-4476-91d0-856fbdf4a958</m:relatesTo>
</m:path>

</soap:Header>
<soap:Body>
<r:queryResponse
xmlns:r="http://schemas.xmlsoap.org/ws/2001/10/referral">
<r:ref>
<r:for>
<r:exact>soap://bettie.example.com</r:exact>
</r:for>
<r:if/>
<r:go>
<r:via>soap://bettie.example.com</r:via>
</r:go>
<r:refId>uuid:fa469956-0057-4e77-962a-81c5e292f2ae</r:refId>
</r:ref>
</r:queryResponse>
</soap:Body>
</soap:Envelope>

Notice that the entire referral statement that matches the supplied for value is returned inside a queryResponse block in the message body. If multiple referral statements match the query, each is returned in a separate ref block. Referral queries provide a way to get a referral statement from a SOAP router. The second part of the referral negotiation mechanism involves registering a referral statement at a second SOAP router.

Referral Registration

A Web service router can request that another router either accept or reject a referral statement. Like a referral query, referral registration is a two-way message exchange. A registration request from Fred to Tom might look like this:

 <soap:Envelope xmlns:soap="http://www.w3.org/2001/09/soap-envelope"> 
<soap:Header>
<m:path xmlns:m="http://schemas.xmlsoap.org/rp/">
<m:action>
http://schemas.xmlsoap.org/ws/2001/10/referral#register
</m:action>
<m:to>soap://tom.example.com</m:to>
<m:rev>
<m:via/>
</m:rev>
<m:id>uuid:cf014249-0e2a-4f8b-9002-13a7de916be0</m:id>
</m:path>

</soap:Header>
<soap:Body>
<r:register xmlns:r="http://schemas.xmlsoap.org/ws/2001/10/referral">
<r:ref>
<r:for>
<r:exact>soap://bettie.example.com</r:exact>
</r:for>
<r:if/>
<r:go>
<r:via>soap://bettie.example.com</r:via>
</r:go>
<r:refId>uuid:fa469956-0057-4e77-962a-81c5e292f2ae</r:refId>
</r:ref>
</r:register>
</soap:Body>
</soap:Envelope>

In this example, Tom is requested to register the referral to Bettie that we saw earlier. If Tom accepts the referral statement, the statement is appended to the referral cache and a positive registration response is generated as follows :

 <soap:Envelope xmlns:soap="http://www.w3.org/2001/09/soap-envelope"> 
<soap:Header>
<m:path xmlns:m="http://schemas.xmlsoap.org/rp/">
<m:action>
http://schemas.xmlsoap.org/ws/2001/10/referral#registrationResponse
</m:action>
<m:to>soap://fred.example.com</m:to>
<m:id>uuid:e5e8d792-abe7-4476-91d0-856fbdf4a958</m:id>
<m:relatesTo>uuid:fa469956-0057-4e77-962a-81c5e292f2ae</m:relatesTo>
</m:path>

</soap:Header>
<soap:Body>
<r:registrationResponse
xmlns:r="http://schemas.xmlsoap.org/ws/2001/10/referral"/>
</soap:Body>
</soap:Envelope>

The presence of the registrationResponse element indicates that the registration succeeded. If Tom fails to accept the referral, a fault is generated as follows:

 <soap:Envelope xmlns:soap="http://www.w3.org/2001/09/soap-envelope"> 
<soap:Header>
<m:path xmlns:m="http://schemas.xmlsoap.org/rp/">
<m:action>
http://schemas.xmlsoap.org/ws/2001/10/referral#registrationResponse
</m:action>
<m:to>soap://tom.example.com</m:to>
<m:id>uuid:e5e8d792-abe7-4476-91d0-856fbdf4a958</m:id>
<m:relatesTo>uuid:fa469956-0057-4e77-962a-81c5e292f2ae</m:relatesTo>
</m:path>

</soap:Header>
<soap:Body>
<soap:Fault xmlns:r="http://schemas.xmlsoap.org/ws/2001/10/referral">
<faultcode>r:registrationFault</faultcode>
<faultstring>Registration Fault</faultstring>
<detail>
<r:maxTtl>36000000</r:maxTtl>
</detail>
</soap:Fault>
</soap:Body>
</soap:Envelope>

Using query and registration requests , it s possible to dynamically maintain a routing topology by adding or removing referrals when necessary. The invalidates element is used to dynamically remove a referral statement from the cache. When an accepted referral contains an invalidates element, its child vid element references another referral that should no longer be used.

Unfortunately, dynamic referral registration is an ideal mechanism for staging man-in-the-middle attacks. If a malicious user can trick a router into accepting a counterfeit referral, that router can then be used to send all subsequent messages to a malicious service. For this reason, before a SOAP router accepts a referral from another SOAP router, a secure level of trust must first be established between the two routers. At a minimum, both parties should be using digital signatures and a trusted mechanism to establish mutual authentication between both services, such as are described by WS-Security and WS- SecureConversation, which I discuss in Chapters 5 and 8, respectively.

As an alternative to the referral query and registration exchange processes, WS-Referral also permits referral statements to be transported in the SOAP message header, which lets you essentially piggyback referrals with regular SOAP messages. When you do this, the collection of referrals is sent within the referrals block in the SOAP header. In this type of exchange, good security practices should still be observed .

WSE Support for WS-Routing and WS-Referral

The support for WS-Routing and WS-Referral in WSE is implemented in the routing and referral pipeline filters. When you send a Web service request using WS-Routing, WSE lets you add one or more Path objects to the SoapContext for the outgoing message. Within the Path object, you can define a collection of Via objects in the Fwd object that defines the endpoints along the forward message path for each desired destination on the message path. When the message is processed by the routing output filter, this information is used to generate the prescribed routing header, which conforms to WS-Routing.

Likewise, the routing input filter processes the routing header information for incoming messages, generates a Path object related to the SoapContext object for the incoming message, and removes the routing header information. This routing information persists in the SoapContext for this message until all other message processing is complete and the message is ready to be forwarded to the next Web service in the message path. When the message is sent, it s processed by the routing output filter, where the routing header is re-created using the persisted path information. The new request message is then sent on to the next SOAP router in the message path.

WSE manages referral statements locally using a referral cache, which is denoted by the referrals element and contains a referral element for each referral that the local service knows about. Before an incoming message hits the routing input filter, it s handled by the referral input filter. This filter checks the incoming message for referral headers and referral query or registration requests. If referrals exist, the filter generates a ReferralCollection object to contain the referral header information. The filter also scans the message routing path for any matches with referral statements stored locally in the referral cache. When matches are found, the values of the via elements are modified according the rules in the referral statement.

Configuring WSE for Routing and Referral

WSE can automatically invoke custom routing logic to implement decision-based routing for your Web service. The WSE documentation provides examples of how to write a logic-based routing handler that is derived from the Microsoft.Web.Services.Routing.RoutingHandler class. After writing a custom routing handler, you need to configure WSE to invoke this handler. While you can configure WSE routing and referral by modifying the ASP.NET configuration file, the easiest method to enable routing and referral is that of using the WSE Settings tool. Using this tool, you can add a custom routing handler that will be invoked by WSE, and you can also specify a referral statement to be used locally as the referral cache. Figure 4-1 shows the Routing tab of the WSE Settings tool.

click to expand
Figure 4-1: WSE routing and referral settings

To configure a custom SOAP message router based in WSE, the WSE routing input filter needs to know which incoming requests to handle and which routing handlers to invoke. This information is specified in the Routing Handlers section of the Routing tab, shown in Figure 4-2. To add a new routing handler:

  1. Click the Add button under Routing Handlers.

  2. Enter the namespace and class of the custom routing handler that s derived from the Microsoft.Web.Services.Routing.RoutingHandler class in the following format:

     Namespace.HanderClass, Handler.dll 
  3. Specify a value for Path, where the default value *.asmx handles all incoming requests to an ASP.NET Web service.

  4. Specify a value for Verb, where the default value * handles all incoming SOAP actions.

    click to expand
    Figure 4-2: WSE routing handler input

To enable the processing of referral statements, the WSE referral input filter needs to know which configuration file contains the referral cache. To specify the referral cache file, enter the file name and full path to the local referral cache file in the Referral Cache field in the WSE Settings tool. The specified referral cache file cannot be read-only, and WSE must have read and write permissions on the file. For security reasons, the access permissions must be set on any file used as the referral cache so that only the account under which WSE is running is able to access the referral cache. WSE typically runs under the ASPNET machine account, although this can be changed in the Machine.config file. Also, this file should have the .config file extension since files with these extensions are treated more securely by the .NET Framework.

Using WSE to Create a Routing Header

The following sample shows how to programmatically create a routing header for an outgoing request message to the DocumentService that requests that the message be routed to the SOAP routers named Tom, Fred, and Bettie before arriving at the ultimate destination of the service.

 // Create an instance of the service proxy. 
DocumentServiceWse myService = new DocumentServiceWse();

// Get that SoapContext of the outgoing request message
SoapContext myContext = myService.RequestSoapContext;

// Specify three SOAP routers to use
string[] routers = new string[3] {"Tom","Fred","Bettie"};

// Add the three routers to the forward message path in the
// SoapContext for the outgoing request message.
for (int i=0;i<routers.Length;i++)
{
// Set the URI for the router
Uri myUri = new Uri("http://example.com/" + routers[i]);

// Add a new via element for this URI.
myContext.Path.Fwd.Add(new Via(myUri));
}

// Call the proxy GetDocument method
XmlDocument myDoc = myService.GetDocument();

// Return the XML document from the Web service.
return myDoc;

Although I don t show it here, there should be a good business reason for having the request message follow such a complex path, such as if each endpoint needs to add SOAP headers to the message. This code results in the routing output filter generating the following SOAP message:

 <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Header>
<wsrp:path soap:actor="http://schemas.xmlsoap.org/soap/actor/next"
soap:mustUnderstand="1" xmlns:wsrp="http://schemas.xmlsoap.org/rp">
<wsrp:action>
http://example.com/DocumentService/GetDocument
</wsrp:action>
<wsrp:to>
http://example.com/DocumentService/DocumentService.asmx</wsrp:to>
<wsrp:fwd>
<wsrp:via>http://example.com/Tom</wsrp:via>
<wsrp:via>http://example.com/Fred</wsrp:via>
<wsrp:via>http://example.com/Bettie</wsrp:via>
</wsrp:fwd>
<wsrp:id>uuid:fb1e5695-c10d-4c5f-be94-96583e09b72c</wsrp:id>
</wsrp:path>
<wsu:Timestamp
xmlns:wsu="http://schemas.xmlsoap.org/ws/2002/07/utility">
<wsu:Created>2003-03-10T02:48:57Z</wsu:Created>
<wsu:Expires>2003-03-10T02:53:57Z</wsu:Expires>
</wsu:Timestamp>
</soap:Header>
<soap:Body>
<GetDocument xmlns="http://example.com/DocumentService/" />
</soap:Body>
</soap:Envelope>

Using WSE to Create a Referral Statement

While WSE uses the referenced referral cache document to automatically forward Web service requests as specified in the referrals, WSE also lets you programmatically construct a referral statement that can be added to either the SoapContext of an outgoing message or the QueryResponse or Registration object in a referral exchange. The following example adds code to the preceding example that generates a simple referral statement in the SOAP header of the request message, requesting that messages sent via Tom be forwarded directly to Bettie.

 // Construct the simple referral statement that refers messages 
// to Tom directly to Bettie, bypassing Fred.
Referral myRef = new Referral();
myRef.For.Exact = new Uri("http://example.com/Tom");
myRef.Go.Add(new Via(new Uri("http:// example.com/Bettie")));

// Add the referral statement to the SoapContext of the request message.
myContext.Referrals.Add(myRef);

This additional code will result in a SOAP message with both routing and referral information in the header, as follows:

 <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Header>
<wsrp:path soap:actor="http://schemas.xmlsoap.org/soap/actor/next"
soap:mustUnderstand="1" xmlns:wsrp="http://schemas.xmlsoap.org/rp">
<wsrp:action>
http://example.com/DocumentService/GetDocument
</wsrp:action>
<wsrp:to>
http://example.com/DocumentService/DocumentService.asmx</wsrp:to>
<wsrp:fwd>
<wsrp:via>http://example.com/Tom</wsrp:via>
<wsrp:via>http://example.com/Fred</wsrp:via>
<wsrp:via>http://example.com/Bettie</wsrp:via>
</wsrp:fwd>
<wsrp:id>uuid:3c1394dd-1b9b-4e92-b3c8-07c039e7c08d</wsrp:id>
</wsrp:path>
<r:referrals soap:actor="http://schemas.xmlsoap.org/soap/actor/next"
xmlns:r="http://schemas.xmlsoap.org/ws/2001/10/referral">
<r:ref>
<r:for>
<r:exact>http://example.com/Tom</r:exact>
</r:for>
<r:if />
<r:go>
<r:via>http://example.com/Bettie</r:via>
</r:go>
<r:refId>uuid:4401d9ee-db8c-49bb-a1a6-00da5d8345b2</r:refId>
<r:desc />
</r:ref>
</r:referrals>
<wsu:Timestamp
xmlns:wsu="http://schemas.xmlsoap.org/ws/2002/07/utility">
<wsu:Created>2003-03-10T06:08:31Z</wsu:Created>
<wsu:Expires>2003-03-10T06:13:31Z</wsu:Expires>
</wsu:Timestamp>
</soap:Header>
<soap:Body>
<GetDocument xmlns="http://example.com/DocumentService/" />
</soap:Body>
</soap:Envelope>

Keep in mind that since the referral filter is executed before the routing filter, if this referral is accepted, the message can be routed directly to Bettie from Tom without having to go though Fred.




Understanding Web Services Specifications and the WSE
Understanding Web Services Specifications and the WSE (Pro Developer)
ISBN: 0735619131
EAN: 2147483647
Year: 2006
Pages: 79

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net