Sergey Shishkin

on agile software development

Web Service Addressing

I was recently hunting down an issue with accessing a WSE 3.0 web service hosted in a custom application. Symptoms are very familiar: a client can access the service only using exactly the same URL as was used to set up a listener on the server; i.e. if I set up a listener on "soap.tcp://localhost/my-service/", I can not access it neither on "soap.tcp://127.0.0.1/my-service/" nor on "soap.tcp://localhost:8081/my-service/" nor even on "soap.tcp://machinename/my-service/", which all obviously point to the same location.

In this small article I’ll try to explain why does this issue happen and will provide a solution.

.NET supported web services development starting from its very first version. Web services were nothing but an extension to ASP.NET and therefore relied on much of ASP.NET infrastructure. Including hosting. To host an ASP.NET web service all we need was to put an ASMX file defining the service on the web server (Internet Information Services for instance) and hook the ASP.NET pipeline to handle it. The only transport, supported out of the box, was obviously HTTP. And we didn’t care much, while relying on ASP.NET and a web server. Clients were invoking the service with any URL as long as it pointed to the hosting machine and the requested ASMX file on its web server.

Later came Web Services Enhancements (WSE) which allowed communicating true WS-* protocols and custom hosting of web services. More power brings more complexity. I case of custom hosting, we now can control (meaning have to think about) which network interfaces the service should listen on. Moreover, on the same network interface and port multiple web services can be identified by their unique names. To call such a service a simple URL is not enough anymore.

WS-Addressing specification addresses 🙂 exactly this issue, providing the endpoint reference element (EPR). EPR differentiates service identification and service location storing them in its "address" and "via" elements respectively. When initialized, a listener uses the "via" element to bind required networking sockets, and the "address" element to identify a service when it receives a message on one of its bound network interfaces.

In the simplest case—which is illustrated in almost all samples and tutorials—ERP will be created with only one URL for both "address" and "via" elements. Obviously, a different URL on the server and on the client leads to the abovementioned issue, because the server compares the "address" elements to identify the requested service.

A far more better approach would be to use a Uniform Resource Name (URN, e.g. "urn:my-services:one-of-them") as the "address" of the service separate from its "via". "Via" on the server could be, for example, "soap.tcp://0.0.0.0/" for listening on all available network interfaces on port 8081 (default port for soap.tcp transport). The client on its side could use as "via" in this case any URL, that points to the port 8081 on the server.

Understanding WS-* specifications, such as WS-Addressing, is very important for developing connected systems using WSE and/or WCF because WS-* is a native object model for both frameworks. Unfortunately, we developers under pressure of time tend to blindly copy-and-paste samples and tutorials into production code, leaving understanding of concepts for a better time. The only thing we all can do about it is to try to make sample code as much as possible appropriate for production. But it’s a topic for another article 😉

Advertisements

Written by Sergey Shishkin

22.11.2007 at 02:45

Posted in Uncategorized

%d bloggers like this: