Web services are becoming an ever-more-critical part of the application development lifecycle. New apps can incorporate new functionality quickly by consuming Web services, and can expose their APIs in the same manner. XML-based Web services, because they use the SOAP standard for remote method invocation, are also turning into a simple vehicle for application integration.
Well, actually, it's not simple. While the first Web services implementations, which relied upon little more than SOAP and XML as well as WSDL files to define SOAP calls, were simple, they were also limited in scope and suitable only for simple inter-process communications under controlled circumstances. The messaging infrastructure simply wasn't defined in a robust manner: There was no standardized way of ensuring receipt or handling queuing, setting priorities, defining routes or alternative paths, securing a message. While developers could add that functionality to Web services, they really had to roll their own.
But thanks to evolving specifications from independent bodies like OASIS and the W3C, as well as work by done by some of the industry's biggest software companies, a more robust messaging infrastructure has been layered on top of Web services--a messaging infrastructure with much of the functionality of heavy-weight message bus and message queuing systems, but with the added benefits of platform portability and a light-weight programming model.
Within the .NET world, the way to code to those additional specs is via Web Services Enhancements, an add-on to Visual Studio .NET and a free-to-redistribute runtime for the .NET Framework.
In an earlier article, "Advanced Web Services the Wizzy Way with WSE," we focused on the security mechanisms that are provided by these specifications. Now, let's take a more detailed look at the new messaging capabilities provided by Web Services Enhancements.
Intelligent End-Point Addressing
The baseline Web services specs assumed that SOAP messages would be transmitted using ordinary HTTP-based GET and PUT methods. While that may be appropriate when using a Web server as the host of the Web services (such as through ASP.NET), it can cramp a developer's style when implementing a non-Web-based application that wants to use SOAP as message transport. Or let's say you have an application that needs to broadcast unsolicited Web services data, such as to a subscriber. In either of those cases, GET/PUT over HTTP isn't the best way to go.
If you want to transmit SOAP messages over a generic TCP/IP service, or go beyond HTTP's GET/PUT, you'll need something more robust. That's handled by WS-Addressing one of the most important specs added to the core Web services pantheon based on work by BEA, IBM, Microsoft, SAP and Sun.
For a detailed description of WS-Addressing, see this article, "Web Services Addressing (WS-Addressing)," on the MSDN site. But it's not necessary to get into all the nuts and bolts to see how WS-Addressing fills a major hole in the protocol stack. First, and most fundamentally, WS-Addressing expands the SOAP header to include referenceable endpoints--something that in the HTTP GET/PUT world is handled by the HTTP header, not by SOAP. Those endpoints, presented as a URI (universal resource identifier), can be a specific machine, a named process, or some other resource. There's a lot of flexibility there, especially if those endpoints are being dynamically generated.
This dynamic generation of endpoints is a core design point of the WS-Addressing spec. The specification allows developers (and systems administrators) some leeway when determining the binding for that endpoint's URI. A client application, for example, may not know exactly which machine or process will end up being the true processor of the Web service's SOAP call; it might instead set the URI to refer to a specific policy, and then leave another application or a Web services router to insert the binding at a later time. Dynamic endpoints can also be exploited by systems that are being managed by a load balancer, or which are hidden behind a network address translation-based firewall.
Another way WS-Addressing goes beyond HTTP-based routing of Web services messages: It allows the SOAP header to specify multiple endpoints, such a default destination endpoint as well as a fault endpoint which identifies a machine or process if there's a fault in processing the Web service, or if the primary default endpoint is unreachable.
Matters of Statefulness
When Web services were first introduced, they -- like the HTTP GET/PUT protocol they relied upon -- were assumed to be stateless. One message out, one message back. But as we all know, while there are conceptual benefits to a stateless model, especially when it comes to managing a heavily laden server, it can come back to haunt us later.
Many real-world client/server transactions are best conceptualized as stateful; first you check a price, then you put something into a shopping cart, and then you check out. Sometimes the state transitions are obvious, sometimes they're not -- when, in that simple e-commerce example, do you log into the server? It could be any time, or not at all.
Web applications have evolved elaborate mechanisms, such as cookies, to manage state, but they all involve some degree of inefficiency. Worse, some of them add complexity in a larger-scale distributed deployment. What if your check-out machine is different than your shopping-card machine, and what if the shopping-card machine is behind a load balancer? Some amount of intelligent infrastructure must be designed into the system to make everything seamless.
Now, translate that to the Web services world. State is important, but how are you going to handle it? Cookies? I don't think so. As applications and transactions get more complex, and as Web services evolve to handle sophisticated message-handling needs such as multi-party communications, two-phase commit with rollback, time delays between messages, offline processing, etc., the system has to be able to handle state.
The answer is also part of the WS-Addressing spec. There are two mechanisms at play. The first is a unique message ID. This message ID might be used to track messages and their responses in a database, to allow a client or router to retransmit a message if it didn't get a response (and for the server to know that it's a duplicate, if it checks its log). The second mechanism allows a message to be identified as being related to another message.
The obvious use of the association is to align a response with a query -- a way of implementing GET/PUT. But it can be more complex than that. Let's say that a query asked for information about a transaction. The immediate response (the PUT to the GET, as it were) can provide that requested data, or simply acknowledge the request. However, let's say that more information becomes available. A later message from the server back to the client could simply reference that first query's message ID.
Could that be handled in other ways? Of course: The developer could come up with his/her own message identification scheme in the XML payload of the SOAP message. But the point here is that this is a standard scheme that could be used in e-commerce, in application integration projects, or elsewhere -- and it can be handled in the SOAP header entirely. That can accelerate message processing and routing, and also allow these associations to be handled by machines that don't have access to the XML payload, if it's encrypted.
There's More to WS-Addressing
There's a lot of flexibility in the WS-Addressing specification, going far beyond what's available to developers simply by programming to ordinary SOAP messaging and HTTP headers. Best of all, it's all contained within
Web Services Enhancements 2.0 , which adds the spec into VS.NET and provides the redistributable runtime.
WSE (See Sidebar 1, WSE 2.0 Service Pack 1) offers other standards-based specs, including security, content-based routing, binary attachments and more. Why not check it out today? You can't beat the price -- free.