Looking Closely at the SOAP Specification


SOAP was developed to be simple. It is a lightweight protocol that is used in the communication of messages from one point to another. It works in a decentralized and distributed environment, typically using HTTP as its mode of transport (although, as I stated, this is not a requirement). The SOAP specification itself is made up of the following parts, which are covered in this chapter:

  • q A description of the SOAP envelope and how to package a SOAP message so that it can be sent via a transmission protocol such as HTTP

  • q The serialization rules for SOAP messages

  • q A definition of the protocol binding between SOAP and HTTP

  • q The capability to use SOAP for RPC-like binding

One of the more important aspects of the SOAP specification is the makeup of the SOAP message or SOAP packet. Be sure you understand the structure of this packet in order to extend and mold it within your own Web services.

To understand it better, take a closer look at the SOAP message and all its parts.

The SOAP Message

The SOAP message is simple, and it was meant to be just that. The SOAP message is what is sent over the wire generally using HTTP, with or without the HTTP Extension Framework (HTTP-EF). SOAP messages are meant to be one-way. Nothing is built into these messages that warrants any response. SOAP does not contain any built-in functions or methods that cause specific events to be initiated. As you are probably already aware, the SOAP message is an agreed-upon structure of XML. The XML specification is simply used as the means of marking up the data to send.

The problem is that Web services generally require a request and response action to occur. Web services tend to get around this problem by sending the SOAP message within the HTTP request and response messages.

The typical SOAP message consists of a SOAP envelope, header, and body section. The SOAP envelope is a mandatory element that is the root element of the entire package. Within the SOAP envelope is an optional header element and a mandatory body element. Figure 20-2 shows an example of the structure of a SOAP message.

image from book
Figure 20-2

Because this entire message is an XML document, it has a single root element (the SOAP envelope element), just like any typical XML document.

The SOAP Envelope

The first step to understanding this structure is to actually review the pieces themselves. Listing 20-1 shows a typical SOAP 1.1 envelope (minus the body information).

Listing 20-1: The SOAP envelope in SOAP 1.1

image from book
      <?xml version="1.0" encoding="utf-8" ?>      <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"       xmlns:xsd="http://www.w3.org/2001/XMLSchema">         <soap:Body>            <!-- The message contents go here -->         </soap:Body>      </soap:Envelope> 
image from book

SOAP 1.2 is not that much different as you can see in Listing 20-2.

Listing 20-2: The SOAP envelope in SOAP 1.2

image from book
      <?xml version="1.0" encoding="utf-8"?>      <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"       xmlns:xsd="http://www.w3.org/2001/XMLSchema">         <soap:Body>            <!-- The message contents go here -->         </soap:Body>      </soap:Envelope> 
image from book

The SOAP envelope is specified as the root element and is qualified by using the SOAP namespace http://www.schemas.xmlsoap.org/soap/envelope/ in the SOAP 1.1 message, whereas the namespace is http://www.w3.org/2003/05/soap-envelope in SOAP 1.2. This SOAP element, qualified by one of these namespaces in your code, is simply expressed as <soap:Envelope>.

The structures defined here, however, are not an absolute requirement; you could also have simply designed the SOAP message as illustrated in Listing 20-3.

Listing 20-3: An example of another SOAP message structure

image from book
      <?xml version="1.0" encoding="utf-8"?>      <env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope">         <env:Body>            <!-- The message contents go here -->         </env:Body>      </env:Envelope> 
image from book

The SOAP Body

Although not every element of a SOAP message is required in the transmission of the message, the SOAP body element is required within your SOAP message. The SOAP body can be considered the main part of the message, where the data part of the message is housed. The SOAP body contains data that is specific to the method call such as the method name and all the input parameters that might be required by the Web service. Your Web service then uses the SOAP body element to return data to the client. The SOAP body can also contain any error information to be sent back to the client.

Looking at the SOAP Body of the Request

Remember that because request and response SOAP messages are going across the wire, both the request and the response SOAP messages must contain a SOAP body section. If you look more specifically at the request payload that is sent in the SOAP body, notice that its contents map directly to a method that has been exposed through the Web service server. Also note that the required arguments (or parameters) for consuming the exposed method are defined in the payload.

For an example of this, examine a simple Add() Method as exposed out from a C# 2.0 Web service. This is illustrated in Listing 20-4.

Listing 20-4: A simple Add() Method as exposed from a C# 2.0 Web service

image from book
      [WebMethod]      public int Add(int a, int b) {         return (a + b);      } 
image from book

With this Web service in place, you can see that the consumer is required to invoke this remote method by passing in two required parameters-variable a (of type int) and variable b (also of type int). Looking at the actual contents of the SOAP body for the request, you can see that the SOAP body maps directly to the Add() method. This is presented in Listing 20-5.

Listing 20-5: The contents of the SOAP body for the SOAP request

image from book
      <soap:Body>         <Add xmlns="http://www.wrox.com/ws">            <a>20</a>            <b>4</b>         </Add>      </soap:Body> 
image from book

As you can tell from the preceding code example, the method and its parameters are serialized into XML, and the method name is now the first child element of the <soap:Body> element. The parameters of the method are also serialized into XML. The first parameter, variable a, is turned into an <a> element, and the b parameter is converted to a <b> element.

Looking at the SOAP Body of the Response

After a Web service receives this SOAP request, an associated SOAP response from the Web service is sent back to the originating client. Just like the SOAP request that came from the client, the payload of the SOAP body in the response is also serialized into XML.

The response from the request shown in Listing 20-4 is presented in Listing 20-6.

Listing 20-6: The contents of the SOAP body for the SOAP response

image from book
      <soap:Body>         <AddResponse xmlns="http://www.wrox.com/ws">            <AddResult>24</AddResult>         </AddResponse>      </soap:Body> 
image from book

In the case of the response SOAP body message, the method name is turned into an element bearing the same name, but with the word Response tacked onto it. The result that is returned is encased within the <AddResult> element, which is the method name with the word Result appended to it.

The SOAP Header

Unlike the SOAP body element, which is required in each and every SOAP message, the SOAP header portion of the SOAP message is an optional element. This section of the SOAP message is used to provide information that is related to what is contained within the SOAP body element-the metadata of the actual message. The convenient thing about the SOAP header is that the recipient of a message that contains contents in a SOAP header is not required to deal with its contents. The consumer of the message may not want to work with some of the information contained in the SOAP header. Therefore, the recipient need not consume all the SOAP header data points.

What should you be transmitting in the SOAP headers of the Web services that you build? This is really an open question. If you look at the SOAP specification, notice it doesn't really state what should be included. This really means that you can include whatever the heck you want. Some common elements that are added to SOAP headers include the following:

  • q Authentication

  • q Transaction management

  • q Timestamps

  • q Routing information

  • q Encryption information

  • q Digital signing management

Of course, you can use SOAP headers for any number of things, but these points give you a general idea of what you can do. Listing 20-7 shows a sample SOAP header.

Listing 20-7: A sample SOAP header

image from book
      <?xml version="1.0" encoding="utf-8"?>      <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"       xmlns:xsd="http://www.w3.org/2001/XMLSchema">         <soap:Header>            <RequiredServiceHeader xmlns="http://www.wrox.com/ws">               <Username>Bill Evjen</Username>               <Password>Bubbles</Password>            </RequiredServiceHeader>          </soap:Header>          <soap:Body>             <HelloWorld xmlns="http://www.wrox.com/ws" />          </soap:Body>      </soap:Envelope> 
image from book

In this example, the SOAP request includes credentials that are sent in with the SOAP message in order to authenticate the user before a SOAP response is issued to the requestor. As you can see, this is quite a powerful tool.

Note 

Later in this chapter in the section "Working with SOAP Header," I will show you how to build and consume some Web services using SOAP headers in your messages.

The SOAP header element needs to come before the SOAP body declaration in the message. The SOAP header is a child element to the SOAP envelope element. The SOAP header contains a single SOAP header block. This SOAP header block is the <RequiredServiceHeader> section. It is possible to have multiple header blocks contained with in a single SOAP header instance.

This next section reviews some of the attributes that can be placed within a SOAP header block.

The actor Attribute

One possible attribute available for your SOAP header blocks is the actor attribute. Note that this attribute is available only in SOAP 1.1 messages. This attribute is not available in SOAP 1.2. It is replaced with the role attribute (discussed shortly).

The actor attribute allows you to easily assign SOAP header blocks for specific SOAP intermediaries. Remember that not all SOAP messages are going to be sent from point A to point B (point-to-point Web services), but instead, your SOAP messages may travel through any number of middle-men (SOAP intermediaries) along the way. A SOAP intermediary is an application that is capable of both receiving and sending SOAP messages as it comes into contact with them. These intermediaries may also be acting upon information that is contained in a SOAP header block that they are designated to work with.

This means that you might have SOAP header blocks contained in your message that, in some cases, could be intended for one of these SOAP intermediaries and not for the final recipient of the SOAP message. If this is the case, it is possible to use the actor attribute within the SOAP header block to specify that the enclosed header element is intended only for a particular SOAP intermediary that the SOAP message might come in contact with. After the SOAP message is received by the SOAP intermediary, the SOAP header is not forwarded with the rest of the SOAP message.

To specify that the SOAP header is intended for the first SOAP intermediary that the SOAP message comes in contact with, the value of the actor attribute needs to be the URI:

http://www.schemas.xmlsoap.org/soap/actor/next

An example of using the actor attribute in a SOAP header is presented in Listing 20-8.

Listing 20-8: Using the SOAP header's actor attribute

image from book
      <?xml version="1.0" encoding="utf-8" ?>      <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"       xmlns:xsd="http://www.w3.org/2001/XMLSchema">         <soap:Header>            <RequiredServiceHeader             soap:actor="http://schemas.xmlsoap.org/soap/actor/next"             xmlns="http://www.wrox.com/ws">               <Username>Bill Evjen</Username>               <Password>Bubbles</Password>            </RequiredServiceHeader>         </soap:Header>         <soap:Body>            <HelloWorld xmlns="http://www.wrox.com/ws" />         </soap:Body>      </soap:Envelope> 
image from book

If you wish to give the SOAP header block to a SOAP intermediary other than the first (one as shown previously), the value of the actor attribute needs to be the URI of the intended location.

The role Attribute

The role attribute is simply a renamed replacement of the actor attribute. Therefore, if you are using SOAP 1.1, use the actor attribute. If you are using SOAP 1.2, use the role attribute. There is no change in the behavior of this attribute. It is shown in Listing 20-9.

Listing 20-9: Using the SOAP header's role attribute

image from book
      <?xml version="1.0" encoding="utf-8"?>      <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"       xmlns:xsd="http://www.w3.org/2001/XMLSchema">         <soap:Header>            <RequiredServiceHeader             soap:role="http://www.w3.org/2003/05/soap-envelope/role/next"             xmlns="http://www.wrox.com/ws">               <Username>Bill Evjen</Username>               <Password>Bubbles</Password>            </RequiredServiceHeader>         </soap:Header>         <soap:Body>            <HelloWorld xmlns="http://www.wrox.com/ws" />         </soap:Body>      </soap:Envelope> 
image from book

The role attribute value of http://www.w3.org/2003/05/soap-envelope/role/next provides the same meaning as the actor attribute's URI (http://www.schemas.xmlsoap.org/soap/actor/next) when you want to designate the intermediary for which the SOAP message is intended. Besides this standard URI, other possibilities include http://www.w3.org/2003/05/soap-envelope/role/none and http://www.w3.org/2003/05/soap-envelope/role/ultimateReceiver. The …role/none URI means that the defined SOAP header block is not really meant for any particular intermediary, but instead is there for processing by other SOAP header blocks. The …role/ultimateReceiver URI is the default value (even if no role attribute value is specified) and means that the SOAP header block is meant for the last receiver in the chain.

The mustUnderstand Attribute

The SOAP header's mustUnderstand attribute is an optional attribute that enables you to specify whether the end user can ignore the SOAP header. Again, the intermediary that receives the SOAP header is the one that is specified through the use of the actor or role attributes.

The value of the mustUnderstand attribute for SOAP 1.1 is either 0 or 1. If the value is set to 1, the recipient of that SOAP header block must process the SOAP header or fail to receive the entire message. A value of 0 means that the recipient is not required to process the SOAP header. SOAP 1.2 changes the possible values of the mustUnderstand attribute from 0 and 1 to false and true respectively.

SOAP 1.1 Faults

With all the applications that are developed, as you know very well, problems are bound to occur with some of the Web services that people are trying to consume. Simply put, errors happen. When errors occur, due to problems on the server or because of invalid inputs from the client, you want to output an appropriate error message to the client.

This is where the SOAP fault element comes into play. The SOAP fault is contained with the SOAP body and is sent in the payload if an error occurs. Some development platforms output SOAP exceptions automatically on your behalf. After a client receives a SOAP fault message, it can then act upon this message in some logical manner.

For instance, if you send a SOAP message with the mustUnderstand attribute set to true, but the SOAP packet receiving the request doesn't understand the SOAP header, you get a faultcode specifying that the SOAP header was not understood. The SOAP 1.1 packet that is returned to you looks like the one illustrated in Listing 20-10.

Listing 20-10: A SOAP 1.1 fault message

image from book
      <?xml version="1.0" encoding="utf-8" ?>      <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"       xmlns:xsd="http://www.w3.org/2001/XMLSchema">         <soap:Body>            <soap:Fault>               <faultcode>soap:MustUnderstand</faultcode>               <faultstring>System.Web.Services.Protocols.SoapHeaderException:                  SOAP header RequiredServiceHeader was not understood.                  at System.Web.Services.Protocols.SoapHeaderHandling.                   EnsureHeadersUnderstood(SoapHeaderCollection headers)                  at System.Web.Services.Protocols.SoapServerProtocol.                   WriteReturns(Object[] returnValues, Stream outputStream)                  at System.Web.Services.Protocols.WebServiceHandler.                   WriteReturns(Object[] returnValues)                  at System.Web.Services.Protocols.WebServiceHandler.Invoke()               </faultstring>            </soap:Fault>         </soap:Body>      </soap:Envelope> 
image from book

Looking over this SOAP fault, notice that the <soap:Fault> element is contained within the <soap:Body> element. From this simple fault message, you can see what the error is and the details concerning it. To expand upon this, the next section reviews the possible child elements contained within the <soap:Fault> block.

<faultcode>

The <faultcode> element is a SOAP 1.1 specific element. As a child of the <soap:Fault> element, the <faultcode> element is used to give the error code, and thereby inform the consuming application (or developer) about the type of error encountered. The preceding example shows a fault code of MustUnderstand, meaning that a portion of the SOAP message was not understood. The following table defines the possible fault codes at your disposal for a SOAP 1.1 message.

Open table as spreadsheet

Name

Description

Client

The receiver didn't process the request because the request was improperly constructed or is malformed in some way.

Server

The receiving application faulted when processing the request because of the processing engine and not due to any fault of the sender or the composition of the message sent.

MustUnderstand

The SOAP header element had a mustUnderstand attribute set to true and the processing endpoint did not understand it or didn't obey the processing instructions.

VersionMismatch

The call used an invalid namespace for the SOAP envelope element.

One last note on the <faultcode> element is that it is a required element whenever you provide a SOAP 1.1 fault.

<faultstring>

The <faultstring> element provides a human-readable version of an error report. This element contains a string value that briefly describes the error encountered. This element is also required in any SOAP 1.1 fault message.

<faultactor>

The <faultactor> element describes the point in the process where the fault occurred. This is identified by the URI of the location where the fault was generated. This is meant for situations where the SOAP message is being passed among a number of SOAP intermediaries and, therefore, the location where the fault occurred must be identified. This is a required element within the SOAP fault element only if the fault occurred within one of the SOAP intermediaries. If the fault occurred at the endpoint, the endpoint is not required to populate the element, although it can do so.

<detail>

The <detail> element carries the application-specific error information related to the SOAP body element. The fault elements previously described are, in most cases, enough for disclosing the error information. It is always good, however, to have more than enough information when you are trying to debug something. The <detail> element can be used to provide that extra bit of information that can facilitate the debug process. For instance, you can carry the line in the code where the error occurred.

SOAP 1.2 Faults

The purpose of a SOAP fault hasn't changed from SOAP 1.1 to SOAP 1.2, but instead, the structure of the SOAP 1.2 fault message has changed. Listing 20-11 shows a typical SOAP 1.2 fault message where the SOAP header was misunderstood because the mustUnderstand attribute was set to true.

Listing 20-11: A SOAP 1.2 fault message

image from book
      <?xml version="1.0" encoding="utf-8"?>      <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"       xmlns:xsd="http://www.w3.org/2001/XMLSchema">         <soap:Body>            <soap:Fault>               <soap:Code>                  <soap:Value>soap:MustUnderstand</soap:Value>               </soap:Code>               <soap:Reason>                  <soap:Text xml:lang="en">                    System.Web.Services.Protocols.SoapHeaderException:                    SOAP header RequiredServiceHeader was not understood.                    at System.Web.Services.Protocols.SoapHeaderHandling.                      EnsureHeadersUnderstood(SoapHeaderCollection headers)                    at System.Web.Services.Protocols.SoapServerProtocol.                      WriteReturns(Object[] returnValues, Stream outputStream)                    at System.Web.Services.Protocols.                      WebServiceHandler.WriteReturns(Object[] returnValues)                    at System.Web.Services.Protocols.                      WebServiceHandler.Invoke()                  </soap:Text>               </soap:Reason>            </soap:Fault>         </soap:Body>      </soap:Envelope> 
image from book

Looking over this SOAP 1.2 fault message, you can see that the <soap:Fault> element is contained within the <soap:Body> element just as it is in SOAP 1.1. The difference lies in the child elements that are contained within the <soap:Fault> element itself. These child elements are reviewed next.

<Code>

The <Code> element is a mandatory element in a SOAP 1.2 fault message. This is a section where you can define the error codes that triggered the error message in the first place. This parent element can contain one or two possible child elements: <Value> and <Subcode>. Each of these child elements are discussed in the following sections.

<Value>

A <Value> element is a mandatory element that is nested within the <Code> element. Like the <fault- code> element from a SOAP 1.1 fault message, the <Value> element is used to specify a high-level SOAP fault code. Possible values for the <Value> element are shown in the following table.

Open table as spreadsheet

Name

Description

Sender

The receiver didn't process the request because the request was improperly constructed or is malformed in some way.

Receiver

The receiving application faulted when processing the request because of the processing engine and not due to any fault of the sender or the composition of the message sent.

DataEncodingUnknown

Either the SOAP header block or SOAP body element used an encoding that the Web service doesn't support.

MustUnderstand

The SOAP header element had a mustUnderstand attribute set to true and the processing endpoint did not understand it or didn't obey the processing instructions.

VersionMismatch

The call used an invalid namespace for the SOAP envelope element.

<Subcode>

The <Subcode> element is an optional element. This element allows you to specify errors that might occur with specific elements. If you use this element, you have to provide a child <Value> element to the <Subcode> element to communicate an error type, as shown in the preceding table.

<Reason>

The <Reason> element has the same purpose as the <faultstring> element from SOAP 1.1. The <Reason> element can contain one or more child <Text> elements that define a human-readable error report.

<Text>

The <Text> element contains the textual string that provides a human-readable error report. This is a child element of the <Reason> element. A <Text> element must contain the lang attribute that defines the language used in the contents of the <Text> element. For instance, in the example from Listing 20-11, you can see that English is used as a value of the <Text> element's lang attribute.

      <soap:Text xml:lang="en">         <!-- Contents removed for clarity -->      </soap:Text> 

<Node>

If you are routing a message through one or more SOAP intermediaries and one of these intermediaries is the cause of the fault, you must include a <Node> element. The <Node> element defines the URI of the SOAP intermediary which caused the fault to occur.

<Role>

The <Role> element defines the role of the node that caused the fault to occur. The possible values are represented in the following table.

Open table as spreadsheet

Name

Description

http://www.w3.org/2003/05/

A SOAP intermediary acting upon the SOAP soap-envelope/role/next message.

http://www.w3.org/2003/05/

The end and ultimate receiver of the SOAP soap-envelope/role/ultimateReceiver message.

<Detail>

The <Detail> element has the same meaning here as the <detail> element does in SOAP 1.1.

SOAP Encoding of Data Types

Along with the programming language you use to build your Web services, you are passing some specific data types from the methods that the consumers invoke. It doesn't matter if your Web services are written in Java, .NET, or something else. That data is being sent across the wire as a SOAP message. Therefore, the data type that is sitting on the SOAP payload needs to maintain its specified data type so that, on the receiving end, the data can be interpreted correctly. For instance, if your method returns an integer of 22, the value that is received on the other end must remain an integer of 22 and not become a string value of “22”. Changes in the data type value would make dealing with Web services quite difficult.

One of the reasons that Web services are so powerful is that the data types are maintained from point A to point B in the message transmission cycle. The process of converting the data types from the application code to a data type that SOAP recognizes is called SOAP encoding.

The types that are serialized into SOAP are the same types that are specified in the XML Schema specification found at http://www.w3.org/TR/xmlschema-2. These data types are pretty standard, and most of the data types that you want to pass into SOAP can be serialized in a manner that works for you. So, for example, you are easily able to serialize primitive types such as String, Char, Byte, Boolean, Int16, Int32, Int64, UInt16, UInt32, UInt64, Single, Double, Guid, Decimal, DateTime (as XML's timeInstant), DataTime (as XML's date), DateTime (as XML's time), and XmlQualifiedName (as XML's QName).




Professional XML
Professional XML (Programmer to Programmer)
ISBN: 0471777773
EAN: 2147483647
Year: 2004
Pages: 215

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