Soap Overview

The third way to communicate with a web service is through SOAP, a frequently acclaimed technology in the .NET Framework. SOAP stands for Simple Object Access Protocol. SOAP prescribes how components communicate with one another using XML messages. Because SOAP uses XML to exchange information, it can more richly describe the data that is exchanged between a client and component (when compared to the HTTP POST and HTTP GET protocols).

At the heart of the SOAP XML message is the SOAP Envelope, which is a container for information being sent to the recipient. As the following listing demonstrates, the Envelope typically defines the XML namespaces used throughout the message.

<soap:Envelope xmlns:soap="" ... >

--> SOAP Message Contents here </SOAP-ENV:Envelope>

Listing 9.6 SOAP Envelope

As Listing 9.6 shows, the SOAP Envelope is defined in the XML namespace Also defined in this namespace is the Body element. The SOAP Body specifies the actual operations and data to be processed by the recipient—method calls, for example, along with any required parameters. The SOAP Body element is always a child element of the Envelope, as depicted below:

<soap:Envelope xmlns:soap="" >

<soap:Body> ... </soap:Body> </SOAP-ENV:Envelope>

Listing 9.7 SOAP body

As its name implies, SOAP is simple. Beyond the predefined elements such as Envelope and Body, SOAP requires only that the contents of the body be a well-formed XML document. SOAP does not prescribe any standard format for calling remote methods, or passing parameters. The interpretation of the data embedded in the Body is left completely up to the recipient of the message, in our case, the web service.

The SOAP specification also defines the elements Header and Fault as children of the SOAP Envelope. The Header element is used to include optional data for the recipient, and is usually used to implement features such as authentication or transaction management. The Fault element is a standard method of presenting error information within a SOAP message. While a discussion of the Header and Fault elements is beyond the scope of this CodeNote, information and examples of their usage can be obtained at aNET090004.

When you call a web service method with HTTP POST, you pass the method parameters in the message body as a url-encoded string. As long as the data type to be transmitted to the service can be broken up into name-value pairs, HTTP POST is sufficient. Consider a web service method that accepts an ADO.NET Dataset as an input parameter (see Datasets in Chapter 6). There is no way to represent this Dataset as a parameter list of name/value pairs. Thus HTTP POST is not sufficient when complex types (nonprimitive) must be transmitted to and from the web service.

SOAP is very similar to HTTP POST, except that the message body is an XML document instead of a url-encoded string. SOAP has an advantage over HTTP GET/POST by virtue of XML's support for representing complex data types. In the XML Support section of Chapter 6, we showed how XML can be used to represent complex heirarchical data structures. Thus, passing a complex structure (such as a Dataset) to a web service requires writing the XML equivalent of the structure and embedding it as the body of the HTTP message.

Although SOAP is more flexible than HTTP GET or POST, there are situations where GET or POST is more appropriate. XML is verbose, and the hierarchical nature of the data requires elements to be nested within opening and closing tags, as depicted below:


<someElement> someValue </someElement> </someTag>

HTTP GET and POST do not support hierarchical data, so you can get away with simply writing:

someElement = someValue

Compare the HTTP POST and SOAP messages. It is apparent that SOAP messages are significantly longer than their HTTP POST counterparts. When web methods require only primitive data types as parameters, one achieves better performance by using HTTP POST instead of SOAP.

SOAP Example

We will now revisit the default page generated by ASP.NET for the Calculator service's GetRandomNumber() method (Figure 9.1). The default page can be viewed at the following URI:


Scroll down the default page and observe the section entitled SOAP, which displays the SOAP format required to access the Calculator component (recall that this page displays sample HTTP GET, HTTP POST, and SOAP messages). The sample SOAP request message is provided in the following listing:

POST /myservice/Calculator.asmx HTTP/1.1 Host: localhost

Content-Type: text/xml; charset=utf-8

Content-Length: length



<?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:xsi="" xmlns:xsd="" xmlns:soap=""> <soap:Body>

<GetRandomNumber xmlns=""> <x>double</x> <y>double</y> </GetRandomNumber> </soap:Body> </soap:Envelope>

Listing 9.6 Sample SOAP request message

Remember that a SOAP message is an HTTP POST with an XML message body. The first line of Listing 9.6 shows that the POST protocol is being used, and the request URI is the relative path to the Calculator service. Compare this URI with the one used to call the web service with standard HTTP POST (Listing 9.2). Note that when using standard HTTP POST, the URI is of the web service's method, whereas we simply specify the URI of the web service when using SOAP:

POST /myservice/Calculator.asmx/GetRandomNumber (HTTP POST -- Listing 9.2) POST /myservice/Calculator.asmx (SOAP -- Listing 9.6)

The SOAP specification adds the SOAPAction HTTP header to the list of required headers. Note that the SOAPAction header does not point to a valid location on the Internet. Instead, it is the namespace-qualified URI of the requested method.

When calling the service with HTTP POST (Listing 9.2), the Content-Type was set to application/x-www-form-urlencoded, since the message body contains a string of name-value pairs. Since the body of a SOAP message is an XML document, we set the Content-Type accordingly to text/xml (Listing 9.6).

To call the GetRandomNumber() method using SOAP, we need to create an HTTP POST message, set the appropriate headers, and attach a SOAP Envelope (formatted according to Listing 9.6) to the message body. Listing 9.6 highlights that SOAP messages are much more verbose than their HTTP POST counterparts. To call the GetRandomNumber() method with HTTP POST, we passed the parameters as a name-value string, for example:

With SOAP, we no longer assume that a parameter is a simple type that can be expressed by name and value alone. The GetRandomNumber() method is referenced as follows:

<GetRandomNumber xmlns=""> <x> 0 </x> <y> 100 </y> </GetRandomNumber>

Note that x or y could just as easily been objects with child XML elements, each with their own data, allowing support for complex types.

To test calling the Calculator web service via SOAP, we will once again use Visual Basic 6 and the Microsoft XML Component, as we did in the HTTP POST example. Source code and compiled binaries for this example can be found at aNET090005. To create the application yourself, open Visual Basic and create a new Standard EXE. Design a form similar to the following:

Using the code of Listing 9.4 as a template, we once again use the MSXML component to send the SOAP request to the Calculator component. In Visual Basic, double-click on the SOAP Request button (Fig-

Figure 9.4 SOAP example in Visual Basic

ure 9.4) and add the following code to format the SOAP message according to Listing 9.6.

Dim req As New MSXML2.XMLHTTP30 "POST", "/myservice/Calculator.asmx", False 'Set HTTP Headers req.setRequestHeader "Host", "localhost" req.setRequestHeader "Content-Type", "text/xml" req.setRequestHeader "SOAPAction",


'Send the SOAP Message, req.send txtRequest.Text txtResponse.Text = req.responseText

Listing 9.7 Calling the GetRandomNumber() method with SOAP

Note that in Figure 9.4, the top textbox (txtRequest) already contains the SOAP Envelope required to call the Calculator service with parameters x=0 and y=100. Run the application by pressing F5, then click the SOAP Request button. The following information will appear in the bottom text area (txtResponse):

?xml version="1.0" encoding=nutf-8"?> <soap:Envelope xmlns:soap="" xmlns:xsi="" xmlns:xsd=""> <soap:Body>

<GetRandomNumberResponse xmlns=""> <GetRandomNumberResult>96.088118383701953 </GetRandomNumberResult> </GetRandomNumberResponse> </soap:Body> </soap:Envelope>

Listing 9.8 SOAP response message

Compare the response message in Listing 9.8 with the HTTP POST response message in Listing 9.5, and another property of SOAP will become evident: it embeds method results in a SOAP envelope as opposed to the simple XML format used by HTTP GET and HTTP POST.

This example shows that calling a web service with SOAP is a more extensive process than with either HTTP GET or POST. We must first decide on the calling protocol, package and send a properly formatted HTTP request message, and then parse the HTTP response message for the result. Fortunately, the .NET Framework can automate the majority of these operations for us. It can only do this with self-describing information from the component, however, and this is provided by a web service's interface, which is described in WSDL—our next topic.

Given that .NET can abstract these intricate details for us (using proxy classes, which we will examine in the next section), was it necessary to persevere through the preceding example? Remember, you may need to call a web service from a platform where no automation mechanisms exist, in which case you would have to resort to our manual approach (our VB6 example could run on any Win32 environment even without the .NET Framework). In addition, understanding what is occurring behind the scenes is extremely valuable in those esoteric and performance-critical situations where automation may be unacceptable.

0 0

Post a comment