Server-Controlled Routing


Server-controlled routing is the easiest form of routing to implement. It simply allows you to forward a request to a different URL. This all happens without the knowledge of the client that is making the request to the Web service.

You can use this form of routing in several situations. You can use it to forward requests to a specific URL behind a firewall (although the wisdom of doing this would be questionable). Or you might use it if you know that the service you’ll ultimately use is likely to move and you don’t want to have to update all the clients when this occurs.

The Web Service

The Web service we’ll use for this example can be found at http://localhost/wscr/14/TellMe.asmx. As we mentioned, this service exposes the Echo method that returns the URL of the executing Web service as well as the details of the route that the message took.

We could call this method directly, but we wouldn’t see any routing details because our request obviously hasn’t been routed to the ultimate destination. We must configure some routers first.

Server Configuration

As we discussed earlier, to use RoutingHandler we need to change the handler for the router we want to implement, and we add this handler in the same way that we would any other HTTP handler—in the <httpHandlers> section of the web.config file. We simply add an entry to <httpHandlers> for whatever filenames we want to handle. If we want to route all requests to Web services for a given application, we can use *.asmx as the filename; if we want to route only a given request and allow all other requests to be handled by the default handler, we can specify a real filename for the handler, such as RouterA.asmx.

Also, nothing can stop us from specifying a completely new extension for the routers we want to use. We could allow all *.rp requests, for instance, to be handled by RouterHandler. We covered HTTP handlers in more detail in Chapter 5, so if you want a lot more detail, have a look there.

For this first example, we have one router in place, at http://localhost/wscr/14/RouterA.asmx, that forwards any requests that it receives to the TellMe Web service, as shown in Figure 14-2.

click to expand
Figure 14-2: Basic server-controlled routing scenario

If you look at the sample code for this chapter, you’ll see that it does not include a RouterA.asmx file. (It does include a RouterA.wsdl file, but we’ll come to that shortly.) All WSE routers are defined in web.config—they don’t have a physical .asmx file. We configure the server to allow routing for the RouterA.asmx address by adding an HTTP handler for that address to web.config, as follows:

<!-- the TYPE attribute must be on one line  --> <add verb="*" path="RouterA.asmx"   type="Microsoft.Web.Services.Routing.RoutingHandler,Π  Microsoft.Web.Services, Version=1.0.0.0,Π  Culture=neutral, PublicKeyToken=31bf3856ad364e35" />

Once we add the router, we must also specify the details about where we want the request routed. We do this by creating a referral cache document that contains the details of where we want the message routed, specified as described in the WS-Referral specification. As you saw when we looked at WS-Referral in Chapter 12, to forward a request we simply use the <r:exact> element to specify what URL we’re routing and a <r:via> element to specify where we want to route to:

<?xml version="1.0" ?> <r:referrals xmlns:r="http://schemas.xmlsoap.org/ws/2001/10/referral">   <r:ref>     <r:for>       <r:exact>         http://localhost/wscr/14/RouterA.asmx       </r:exact>     </r:for>     <r:if/>     <r:go>       <r:via>         http://localhost/wscr/14/TellMe.asmx       </r:via>     </r:go>     <r:refId>uuid:fa469956-0057-4e77-962a-81c5e292f2aa</r:refId>   </r:ref> </r:referrals>

We now need to tell the RoutingHandler that a referral cache is being used. As with all WSE configuration items, this is done in the <microsoft.web.services> element within web.config, as follows:

<referral>   <cache name="referral.config" /> </referral>

The name attribute contains the filename of the file that contains the referral cache and is placed in the root of the application directory structure.

Note

When you use referral cache files, you must give the ASP.NET account write access to the file you’re using—if you don’t, the routing request to the server will return an UnauthorizedAccessException. Once the ASP.NET process opens this file, you cannot change its contents. If you’re in a live environment, you obviously can’t turn off the server to modify the file, and you need to change the file in place. To do this, you must create a new referral cache file on the server and then change the settings in web.config to point at this new file. Any new requests will immediately use the new referral cache file, and once all the existing requests have been processed, you can delete the old referral cache file.

We’ve now configured RouterA.asmx to forward all incoming requests to the real Web service at TellMe.asmx. However, one thing is still missing from a client perspective. We have no way of adding a reference to the Web service to our project because the router doesn’t have an automatically generated WSDL document—the RouterA.wsdl file that we mentioned earlier now comes into play.

WSDL for the Router

As we mentioned earlier, a router doesn’t have a real endpoint, so it is impossible to automatically generate a WSDL description of it. As we access the WSDL for the service across HTTP, we cannot automatically retrieve it because the router cannot route HTTP requests to retrieve the WSDL for the ultimate destination. If we try to retrieve the WSDL for the Web service in Microsoft Internet Explorer, we get an exception of type NotSupportedException, as shown in Figure 14-3.

click to expand
Figure 14-3: We can’t view WSDL for a router.

We must therefore manually provide a WSDL document for the RouterA.asmx Web service that’s based on TellMe.asmx, the real service we’re routing to. We can do this quite easily by viewing the WSDL for TellMe.asmx, saving it, and changing the reference to TellMe to RouterA. This effort involves a simple Find and Replace within the WSDL document that we’ve saved. The Replace will change names and references in the <portType>, <binding>, <service>, and <port> elements in the WSDL as well as the location attribute of the <soap:address> element:

<soap:address   location="http://localhost/wscr/14/RouterA.asmx" />

We could get away with changing only the <soap:address> element, but changing all references to the original Web service provides a further separation between the router and the service that will actually process the message.

We can use this modified WSDL file for the Web service instead of any automatically generated WSDL. For RouterA.asmx, this is the WSDL file that we mentioned earlier at http://localhost/wscr/14/RouterA.wsdl; we can use this to create the reference to the router.

Note

When you use static WSDL files, remember that the <soap:address> element must be manually changed to match the server that the Web service resides on. This is no longer changed automatically for you when you move between servers.

The Client

As far as the client is concerned, we’re simply accessing a normal Web service. The whole point of routing in this manner is that the client is unaware that the request has been forwarded to another location for processing. We’re not concerned with where the request is executed—only whether the request is executed correctly.

We can add a reference to http://localhost/wscr/14/RouterA.wsdl to the project, and the code that we use to access the Web service will be no different from any code we’ve already written.

You can see this in the RoutingClient application that is among the code samples for this chapter. This client application, which looks more complex than it actually is, demonstrates all the routing options we’ll look at. Each of the three types of routing that we’ll look at has its own tab—for now, we’re interested only in the first tab, Server, as shown in Figure 14-4.


Figure 14-4: The RoutingClient application showing the server-controlled routing tab

As you can see, two option buttons allow you to specify which router you want to call. So far, we’ve looked at RouterA.asmx only, so for now you can ignore the RouterB.asmx option—we’ll talk about it later. If we leave the RouterA.asmx option selected and click the Execute button, we’ll call the RouterA.asmx service.

Within the event handler for the Execute button, we first check to see which option was selected and execute the correct block of code. As you can see in the following code, we then simply create an instance of the proxy class and call the Echo method. There is a little bit of error handling around the Web service call, but nothing that you haven’t seen before.

if (radA.Checked == true) {     try     {         // create the proxy         RouterAWse proxy = new RouterAWse();         // call the proxy         MessageBox.Show(proxy.Echo(), "Returned message");     }     catch (Exception error)     {         MessageBox.Show(error.Message, "Error!!");     } }

As you can see in Figure 14-5, if we run the above code we do indeed route to the location we specified in the referral cache.

click to expand
Figure 14-5: Return showing the path that was taken to TellMe.asmx

Although Figure 14-5 shows the client displaying routing details, it has a view of these only because we chose to return them to the client so we could show that the message was actually routed. In a real-life situation, we wouldn’t pass these back to the client, and the message would appear to have been handled by the Web service that we called.

The SOAP Messages

The routing example we’ve been looking at so far takes the simplest possible form. However, changes are still made to the SOAP messages that are passed between the client and the Web service that ultimately handles the request.

When we send a message from the client, the Routing output filter adds a routing header that specifies the address we’re actually sending the message to. As you’ll recall from Chapter 12, these details are contained in the <wsrp:to> element of the <wsrp:path> element of the SOAP header:

<wsrp:to>http://localhost/wscr/14/routing/RouterA.asmx</wsrp:to>

After RoutingHandler.ProcessRequest calculates the correct outgoing path and the call is made to the next router, the Routing output filter populates the <wsrp:path> element with the correct details:

<wsrp:to>http://localhost/wscr/14/RouterA.asmx</wsrp:to> <wsrp:fwd>   <wsrp:via>     http://localhost/wscr/14/TellMe.asmx   </wsrp:via> </wsrp:fwd> 

Multiple Routers on the Same Server

Nothing prevents us from having several routers within the same application, all routing to different locations. However, if we have a chain of routers on the same machine, all controlled using the referral cache, the RoutingHandler.ProcessRequestMessage method will make some optimizations to the path that the message takes. Instead of travelling between the different routers, the message is simply passed directly to the final router in the chain.

This is not what we require, but it actually makes sense. Any routers referenced in the referral cache and handled by RoutingHandler have no other processing performed on them. Why would we pass a request through a series of routers that will do nothing but pass the message onto the next one in the chain?

You can see this in action if we use RouterB.asmx, which we sidestepped earlier. RouterB.asmx is configured in a chain with RouterC.asmx, which then calls TellMe.asmx, as shown in Figure 14-6.

click to expand
Figure 14-6: Server-controlled routing chain

On the server, we added handlers for the two routers to the web.config file, and we also added two new <r:ref> elements to the referral cache. If we hadn’t, as soon as we tried to route through a router without an entry in the referral cache, we’d generate an exception of type SoapHeaderException because we’d have no routing details for the router we defined.

If we now run the RoutingClient application and select RouterB.asmx as the router, we can see that we don’t actually go through RouterC.asmx—we go directly to BasicHandler.asmx. This is shown in Figure 14-7.

click to expand
Figure 14-7: Routing chains on the same server are optimized.

Although RoutingHandler optimized the route we took, we haven’t lost the actual route we should have taken from the <wsrp:path> header—if we were to lose it, we wouldn’t be able to generate the list of paths that we missed in Figure 14-7. When the optimization takes place, the Routing input filter places the unused paths after the optimized path in the <wsrp:fwd> element, as you can see in this extract from the Trace filters on the server:

<wsrp:to>http://localhost/wscr/14/RouterB.asmx</wsrp:to> <wsrp:fwd>   <wsrp:via>     http://localhost/wscr/14/TellMe.asmx   </wsrp:via>   <wsrp:via>     http://localhost/wscr/14/RouterC.asmx   </wsrp:via> </wsrp:fwd>

We had only one missed path here—RouterC.asmx—but if we’d had more, they would also appear as elements in the <wsrp:fwd> element.




Programming Microsoft. NET XML Web Services
Programming MicrosoftВ® .NET XML Web Services (Pro-Developer)
ISBN: 0735619123
EAN: 2147483647
Year: 2005
Pages: 172

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