April 17, 2011, 7:40 p.m.
posted by angryuser
Standards for XML Web Services
Now that we have covered the standards that form the foundation of XML Web Services, we should examine the standards that make up its core: SOAP and WSDL.
The Protocol: SOAP
SOAP 1.1 is the protocol that drives XML Web Services. In order to send a message from one machine to another, you need a protocol: a description of rules and formats for that communication. Although many protocols have been developed, most have been tied to a particular operating system or development platform. SOAP is a simple protocol that was developed for compatibility with many different platforms and operating systems, and it enables machine-to-machine communication in very heterogeneous environments.
At its core, SOAP describes very simple XML-based packaging for sending messages. It also includes optional descriptions for how to use this packing mechanism with RPCs (remote procedure calls), as well as with HTTP. A SOAP message can look as simple as this:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <Test /> </soap:Body> </soap:Envelope>
Notice that the overall wrapper is called <Envelope>. Within this is another child tag (of which there can be only one) called <Body>. Within this tag is whatever information the message contains.
So why two elements? Because within <Envelope> you can also find the <Header> tag. SOAP headers pass interesting information and extend the SOAP architecture. For example, you could use headers to pass transaction information, or information about the digital signature of the SOAP message. You could also use them for routing information. Listing 2.2 shows an example of a SOAP message that uses headers for routing, following the WS-Routing specification. (You can learn more about WS-Routing in Chapter 12, Messaging with Web Services: WS-Routing, WS-Referral, and DIME.)
<SOAP:Envelope xmlnsoap:S="http://schemas.xmlsoap.org/soap/envelope/"> <SOAP:Header> <m:path xmlnsoap:m="http://schemas.xmlsoap.org/rp/"> <m:action>http://contoso.com/Update</m:action> <m:to>soap://contoso.com/Endpoint/Update</m:to> <m:id>uuid:11777523-546b-6751-8989-5dsf35sgs5d6</m:id> </m:path> </SOAP:Header> <SOAP:Body> <Test /> </SOAP:Body> </SOAP:Envelope>
Headers are useful, but what actually makes a SOAP message interesting is what you put inside the <Body> tag. There are two major things that people do with SOAP: document passing and remote procedure calls. Each of these impacts what goes inside the <Body>.
The SOAP standard also states that you can send SOAP over whatever transport you want, from UDP (User Datagram Protocol), to HTTP, to homing pigeons, to transports not yet invented. However, when you use it over HTTP, SOAP mandates that an additional HTTP header called SOAPAction must be present.
Passing Documents with SOAP
With document passing, the <Body> contains XML. Usually a schema somewhere describes this XML. (When we get to WSDL later in the chapter, you'll see how schemas are included in a complete description of the SOAP message contents.) For example, you may want to send a SOAP message that contains a purchase order, as in Listing 2.3.
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <PurchaseOrder ID="3245"> <From>Jim</From> <To>Frank</To> <Items> <Item ID="111">Dingbats</Item> <Item ID="222">Widgets</Item> </Items> </PurchaseOrder> </soap:Body> </soap:Envelope>
How this purchase order document is to be used and what it signifies are not specified in the SOAP message. For example, it could be an order from a customer, or it could be a supplier's message to accounting servers. Furthermore, the implementation details of how this message was created or how the receiver will handle it are not apparent from reading this message. Not even a preference for how the message should be handled is apparent. Higher level application semantics are needed to answer these questions.
It should be clear by now that SOAP is about sending messages, and nothing more. It doesn't try to be a complete solution in and of itself. Instead, it provides a straightforward and extensible architecture for passing messages.
Remote Method Calls with SOAP
Another use of SOAP (the one where the word Object in Simple Object Access Protocol gets its meaning) can be found in the style of SOAP messages described in the SOAP specification, Sections 5 and 7. This is using SOAP to encode a method call, as in Listing 2.4.
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <SOAP-ENV:Body> <m:GetStockPrice xmlns:m="http://contoso.com/Stock"> <symbol>MSFT</symbol> </m:GetStockPrice> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
This SOAP request maps to a method call fairly well. For example, a corresponding method call in C# would be:
GetStockPrice( "msft" );
Section 5 of the SOAP specification describes a set of XML for encoding data types, such as strings, integers, arrays, and structs. It also describes the XML for encoding polymorphic types. When a SOAP request uses the rules of Section 5, it's common to say that the request was encoded SOAP. Section 5 is completely optional for SOAP use.
Section 7, also optional, describes how to encode a method call within a SOAP message and reply. Of note is that Section 7 says to use the rules of Section 5, and to create an encoded struct, with the root element of the struct being the name of the method, and each accessor of the struct being a parameter. For example:
<m:GetStockPrice xmlns:m="http://contoso.com/Stock"> <symbol>MSFT</symbol> </m:GetStockPrice>
This is the method call modeled as a Section 5 encoded struct. Section 7 specifies that the response to the method call will be modeled as a struct as well. It also states that the parent element name doesn't matter. For example:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <SOAP-ENV:Body> <m:GetStockPriceResponse xmlns:m="http://contoso.com/Stock"> <return>120</return> </m:GetStockPriceResponse> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
This kind of SOAP, when Sections 5 and 7 are used together to model method calls, is commonly called Rpc/Encoded SOAP.
SOAP is really at the crux of Web services in many ways, and we'll discuss it in almost every chapter. But Chapter 9 (The Messaging Protocol: SOAP) gives it more in-depth focus.
Describing Services with WSDL
Let's pretend you have a Web service that exposes two operations: one receives new purchase orders, and the other updates current purchase orders. How do you describe to potential users of the service the details needed to call it? One way is to write a document with samples. But this kind of documentation would require users to build their clients by hand, and unless your samples included all possible permutations of allowable messages, they might not create something all that robust.
You could send them the schema of the messages your service expects to receive. You could say, I have this operation for saving, and the request message should conform to this schema, and the response I return will conform to this schema. That's a little better.
Or, you could use WSDL, the Web Services Description Language. WSDL 1.1 is the current version of this language. It's an XML-based syntax that relies heavily on XSD Schemas, to describe everything a SOAP service needs to describe the following:
Listing 2.5 shows an example of a short WSDL document that describes an integer addition service.
<?xml version="1.0" encoding="utf-8"?> <definitions xmlns:s="http://www.w3.org/2001/XMLSchema" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s0="http://tempuri.org/" targetNamespace="http://tempuri.org/" xmlns="http://schemas.xmlsoap.org/wsdl/"> <types> <s:schema attributeFormDefault="qualified" elementFormDefault="qualified" targetNamespace="http://tempuri.org/"> <s:element name="Add"> <s:complexType> <s:sequence> <s:element minOccurs="1" maxOccurs="1" name="a" type="s:int" /> <s:element minOccurs="1" maxOccurs="1" name="b" type="s:int" /> </s:sequence> </s:complexType> </s:element> <s:element name="AddResponse"> <s:complexType> <s:sequence> <s:element minOccurs="1" maxOccurs="1" name="AddResult" type="s:int" /> </s:sequence> </s:complexType> </s:element> <s:element name="int" type="s:int" /> </s:schema> </types> <message name="AddSoapIn"> <part name="parameters" element="s0:Add" /> </message> <message name="AddSoapOut"> <part name="parameters" element="s0:AddResponse" /> </message> <portType name="AddClassSoap"> <operation name="Add"> <input message="s0:AddSoapIn" /> <output message="s0:AddSoapOut" /> </operation> </portType> <binding name="AddClassSoap" type="s0:AddClassSoap"> <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" /> <operation name="Add"> <soap:operation soapAction="http://tempuri.org/Add" style="document" /> <input> <soap:body use="literal" /> </input> <output> <soap:body use="literal" /> </output> </operation> </binding> <service name="AddClass"> <port name="AddClassSoap" binding="s0:AddClassSoap"> <soap:address location="http://localhost/test/add.asmx" /> </port> </service> </definitions>
First, a WSDL document contains a <types> section, which contains a schema. The schema describes all of the XML for all messages this service will process. The <messages> section ties pieces of the schemas to particular messages. Messages are combined into <operations> that reside under <portType> elements. For example, with request–response operations, there is an input message and an output message.
So far, each of these elements and structures within the WSDL document are very abstract. They don't even say anything about SOAP, and they actually could be applied to some protocol other than SOAP. The <Binding> section is what binds these operations to SOAP itself and gives the information, such as the possible SOAPAction HTTP header, needed for this service. Finally, the <Service> tag contains concrete information about where the service exists—in other words, the actual endpoint, or URL, of the service.