The SOAP <Envelope>

A SOAP message is an XML document that consists of a mandatory SOAP <Envelope> root element, an optional <Header> element, and a mandatory <Body> element. Think of this as an envelope used to mail a letter to a friend across the country. The SOAP envelope is analogous to the paper envelope—it displays the routing directions and the letter. The routing directions, or address (to and from) are represented in the <Header> element of a SOAP message. The letter itself is contained in the SOAP body. All this information is necessary to successfully transmit data via the SOAP protocol. Let's begin with a short example to illustrate how SOAP works.

In Listing 14-1, skeletal_soap.xml, we show you a skeletal SOAP message with placeholders for the <Header> and the <Body> information. In a real message these would contain the necessary routing information and payload of the exchange.

Listing 14-1 skeletal_soap.xml: A skeletal SOAP message.

<SOAP-ENV:Envelope
    xmlns:SOAP-ENV=/soap/envelope/"
    SOAP-ENV:encodingStyle=/soap/
encoding/">   <SOAP-ENV:Header>     <!-- (optional) Contextual header information... -->   </SOAP-ENV:Header>   <SOAP-ENV:Body>     <!-- Serialized object information... -->   </SOAP-ENV:Body> </SOAP-ENV:Envelope>

You can also define your own subelements within a SOAP <Envelope>, but they must be namespace-qualified and must come after the <Body> element.

All SOAP messages should include the proper namespace declarations so that SOAP applications can correctly process the messages. The SOAP specification defines two namespaces.

The encodingStyle Global Attribute

The SOAP-ENV:encodingStyle attribute is used to indicate the rules used to encode the information in a particular SOAP message. The default SOAP encoding rules are identified by the namespace. Like any other use of namespaces, this attribute can appear on any element. When applied, its scope is restricted to that element's contents and all child elements not overriding the attribute with their own namespace. Note that no default encoding is defined for a SOAP message, so you must include the encodingStyle attribute at least once in your SOAP messages. Typically you will include it in the <Envelope> declaration itself, as shown in the skeletal_soap.xml example.

You can define your own encoding rules. In that case you will need to define your own schema.

Now let's turn to the <Header> and <Body> elements and take a closer look at how they are specified and work.

<Header>

The <Header> element is used to encapsulate information that is not tied to a specific method invocation, but provides context information instead. Typical examples of <Header> element usage are security, transaction management, and payment information.

There are several rules defined by the SOAP specification for the <Header> element. These are as follows:

To show you an example of how to use the <Header> element, let's make a request to an imaginary language-translation service that translates arbitrary words, paragraphs, or both from one specified spoken language to another. Furthermore, suppose this is a pay-by-use service and that you will need to provide valid authentication information with every request. Listing 14-2, soap_header.xml, shows the <Header> section of such as a request.

Listing 14-2 soap_header.xml: Some example SOAP <Header> elements.

<SOAP-ENV:Envelope
    xmlns:SOAP-ENV=/soap/envelope/"
    SOAP-ENV:encodingStyle=/soap/
encoding/"/>
  <SOAP-ENV:Header>
    <a:Authentication xmlns:a="some-URI">
      <UserID>foo</UserID>
      <Password>an-encoded-password</Password>
    </a:Authentication>
  </SOAP-ENV:Header>
  <SOAP-ENV:Body>
    <!-- Serialized object information... -->
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

In this example we added a custom Authentication <Header> element with a <UserID> and <Password> subelements providing the necessary authentication information. Notice that, as required by the specification, we have properly namespace-qualified our Authentication <Header> element.

mustUnderstand

In soap_header2.xml the concept of authentication is critical to the success of the service request. To ascertain that a service understands and can process a specific <Header> element, you can tag specific <Header> elements with the SOAP-ENV:mustUnderstand attribute. This attribute indicates to a SOAP-compliant processor that the associated <Header> element is critical to the processing of the method call and that, if for some reason the remote SOAP processor is unable to understand or handle it, you don't want the method call to execute. In this case the SOAP processor should simply reject the method call.

The value of the SOAP-ENV:mustUnderstand attribute is either 1 or 0. Listing 14-3, soap_header2.xml, shows the SOAP message soap_header.xml updated to include the SOAP-ENV:mustUnderstand attribute.

Listing 14-3 soap_header2.xml: The SOAP-ENV:mustUnderstand attribute.

<SOAP-ENV:Envelope
  xmlns:SOAP-ENV=/soap/envelope/"
  SOAP-ENV:encodingStyle="/soap/encoding/">
  <SOAP-ENV:Header>
    <a:Authentication xmlns:a="some-URI" SOAP-ENV:mustUnderstand="1">
      <UserID>foo</UserID>
      <Password>an-encoded-password</Password>
    </a:Authentication>
  </SOAP-ENV:Header>
  <SOAP-ENV:Body>
    <!-- Serialized object information... -->
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

With this change in our SOAP message, a SOAP-compliant processor will attempt to process this message only if it can understand our custom <Authentication> <Header> element. If not, the processor will reject this message with a proper response message.

actor

When a SOAP message travels from the originator to its ultimate destination, it does not need to travel directly between the source and destination. The message might pass through a set of SOAP intermediaries, each receiving and then forwarding the message to the next receiver, until the message reaches its final destination. Therefore, not all parts of a SOAP message can be intended for the final destination; some must be directed at one or more of the intermediaries on the message path.

You use the SOAP-ENV:actor attribute to allow a SOAP message to indicate that <Header> information that is relevant to a specific recipient. The value of the SOAP-ENV:actor attribute is a URI used to identify the recipient of the <Header> element. The SOAP specification defines a special URI, , to indicate that the associated <Header> element is intended for the first SOAP recipient, intermediary or otherwise.

Now that we have covered the <Header> and how it is used to provide contextual information for a SOAP message, we can discuss the <Body> element of the SOAP message.

<Body>

The <Body> element contains the actual serialized data of the method call itself. The <Body> element is also used for a method call's response, which will either be the information related to a valid request or a SOAP fault if the call failed. The SOAP specification defines three types of <Body> elements.

  • The Call <Body> contains the information required for a method call, such as the method name and arguments.
  • The Response <Body> contains the response information for a successful method call.
  • The Fault <Body> contains the fault code and other information for an unsuccessful method call.

Call <Body>

The first child element of a Call <Body> element is labeled according to the method name. The embedded elements are the serialized arguments, with each argument named according to the method signature. For example, in our TranslationService method call we might have a method with the following C# signature:

string TranslateText(string SourceLanguage, string TargetLanguage, string Text)

Imagine that you now want to make the following equivalent method call:

// Translates an English sentence to French
string translatedText = TranslateText( "en", "fr", "I speak French" );

Listing 14-4, soap_callbody.xml, shows the equivalent SOAP message.

Listing 14-4 soap_callbody.xml: SOAP Call <body> example.

<SOAP-ENV:Envelope
    xmlns:SOAP-ENV=/soap/envelope/"
    SOAP-ENV:encodingStyle=/soap/encoding/">
  <SOAP-ENV:Header>
    <a:Authentication xmlns:a="some-URI" SOAP-ENV:mustUnderstand="1">
      <UserID>foo</UserID>
      <Password>an-encoded-password</Password>
    </a:Authentication>
  </SOAP-ENV:Header>
  <SOAP-ENV:Body>
    <m:TranslateText xmlns:m="some-URI">
      <SourceLanguage>en</SourceLanguage>
      <TargetLanguage>fr</SourceLanguage>
      <Text>I speak French</Text>
    </m:TranslateText>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Note that, just as in the <Header> element, the <Body> element is namespace-qualified as required by the SOAP specification. You don't need to qualify the argument elements, though, because they are assumed to be identified by the enclosing method element's namespace.

Response <Body>

A Response <Body> contains information the SOAP service returns to the caller after a successful method call. Listing 14-5, soap_responsebody.xml, shows you a sample successful response to the method call made in soap_callbody.xml.

Listing 14-5 soap_responsebody.xml: SOAP Rresponse <Body> example.

<SOAP-ENV:Envelope
    xmlns:SOAP-ENV=/soap/envelope/"
    SOAP-ENV:encodingStyle=/soap/encoding/">
  <SOAP-ENV:Body>
    <m:TranslateTextResponse xmlns:m="some-URI">
      <Text_fr>Je parle Francais</Text_fr>
    </m:TranslateTextResponse>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

The custom is to append the word Response to the original method name. As in the method call, the name of the return arguments, which in soap_responsebody.xml is <Text_fr>, is immaterial as far as the specification is concerned. Finally the element is namespace qualified.

<Fault> in <Body>

When a method call fails, instead of a normal Response <Body>, a SOAP processor will use a <Fault> occurrence in the <Body> of the response SOAP message, as shown in Listing 14-6, soap_faultbody.xml.

Listing 14-6 soap_faultbody.xml: SOAP <Fault> in the <Body>.

<SOAP-ENV:Envelope
    xmlns:SOAP-ENV=/soap/envelope/"
    SOAP-ENV:encodingStyle=/soap/encoding/">
  <SOAP-ENV:Body>
    <SOAP-ENV:Fault>
      <faultcode>SOAP-ENV:Server</faultcode>
      <faultstring>Translator not found</faultstring>
      <detail xmlns:e="some-URI">
        <e:ErrorCode>
          014
        </e:ErrorCode>
        <e:ErrorMsg>
          No suitable Translator found for "en-fr" translation
        </e:ErrorMsg> 
      </detail>
    </SOAP-ENV:Fault>  
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

The SOAP specification requires that <Fault> be the first child element of the <Body> element.

The SOAP specification defines the following subelements:

  • The mandatory <faultcode> element can be used by applications for algorithmically identifying the fault. The <faultcode> values are defined in an extensible manner similar to the 1xx, 2xx, 3xx, and other basic HTTP response codes. However, instead of numeric values the codes are defined as XML qualified names. A . (dot) character separates fault values indicating that what is to the left of the dot is a more generic fault code value than the value to the right (for example, Client.Authentication). SOAP specification defines the fault codes shown in Table 14-1.
  • The mandatory <faultstring> element provides a human-readable explanation of the fault.
  • The optional <faultactor> element provides information about what caused the fault to happen within the message path.
  • The mandatory <detail> element provides application-specific error information related to the processing of the <Body> element. A detail entry, which is an immediate child element of the <detail> element, must be a fully qualified name.
Table 14-1 Fault Codes Defined in SOAP
Fault code Meaning

VersionMismatch

The processor found an invalid namespace for the SOAP element.

MustUnderstand

A <Header> element tagged with the SOAP-ENV:
mustUnderstand
attribute was either not understood
or properly obeyed by the processor.

Client

The message was incorrectly formed or did not contain the appropriate information to succeed. Generally, the message should not be sent again without a change correcting the problem.

Server

The message could not be processed by the processor for reasons not directly attributable to the contents of the message itself, but to the processing of the message.

In addition to these standard elements you can include your own custom subelements within the <Fault> element as long as they are namespace-qualified.

Encoding

So far we've only talked about the structure of a SOAP message and none of the other aspects. In this section we will look at how the arguments associated with a method call are actually encoded, from both a simple and a compound perspective, as well as array encoding and default values.

As we mentioned earlier, you can use the SOAP-ENV:encodingStyle attribute to indicate the encoding style used. SOAP's standard encoding style, the schema of which can be found at , is modeled after typical programming languages like C or C++ (and now C#).

The SOAP specification also refers to the "XML Schema Part 1: Structures" (www.w3.org/TR/xmlschema-1/) and "XML Schema Part 2: Datatypes" (www.w3.org/TR/xmlschema-2/) for encoding message schemas.

In SOAP you can use only elements to represent values within a <Body>. Using attributes for passing arguments is illegal. The elements must be either a simple scalar type defined by the "XML Schema Part 2: Datatypes" specification, an element that encapsulates a SOAP array, or an element whose structure you can ascertain with the help of a schema.

Simple Types

Simple types, such as integers, strings, and floating-point numbers, can be directly encoded in SOAP as elements. The schema for the elements defines the actual types, not the actual SOAP message. In soap_callbody.xml, for example, the three string arguments of the method TranslateText are encoded directly as simple types.

Compound Types

Compound types are encoded like structures or even classes in some programming languages, like C++, C#, and Java. The containing element holds the structure information while the elements within are either simple types or other compound types. The containing element is always qualified with a namespace, while all the contained elements are unqualified. For example, examine the simple C structure in Listing 14-7, c_struct.txt.

Listing 14-7 c_struct.txt: A simple C structure.

struct tag_Person 
{
  string name;
  double age;
} Person;

Now take a look at the corresponding encoded SOAP in Listing 14-8, compound_type.xml.

Listing 14-8 compound_type.xml: An example of Compound_Encoding.

<Person xmlns="someURI">
  <name>Harry</name>
  <age>37</age>
</Person>

Array

The final major type of SOAP encoding is array, which builds on the other types to produce ordered lists of simple or compound datatypes. The special SOAP-ENC:arrayType attribute is used to distinguish a SOAP array from other datatypes. Listing 14-9, array_type.xml, shows how an array of the Person datatype declared in compound_type.xml can be encoded in SOAP.

Listing 14-9 array_type.xml: SOAP array example

<PersonList SOAP-ENC:arrayType="Person[2]">
  <Person>
    <name>Tom</name>
    <age>27</age>
  </Person>
  <Person>
    <name>Dick</name>
    <age>30</age>
  </Person>
</PersonList>

Default Values

Some programming languages, such as C++ and C#, have the concept of default arguments. SOAP by itself does not specify default values. However, with the help of proper schema definition, a SOAP consumer can automatically omit default arguments from the message packet. On the receiving side, a SOAP processor can also automatically invoke the remote method itself with the appropriate default information inserted.

Now that you've learned how to construct SOAP messages, the following section will show you how to implement applications that can produce and consume them.