Share via


Understanding SOAP

 

Aaron Skonnard
DevelopMentor

March 2003

Applies to:
   Global XML Web Services Architecture (GXA)
   Remote Procedure Calling (RPC)
   SOAP 1.1 an SOAP 1.2 specifications
   Transport Protocols: TCP, HTTP, SMTP, and MSMQ
   Web Services Enhancements 1.0 SP1 for Microsoft® .NET
   XML Schema

Summary: SOAP provides a simple, extensible, and rich XML messaging framework for defining higher-level application protocols offering increased interoperability in distributed, heterogeneous environments. (20 printed pages)

Contents

Introduction
SOAP Versions
Messaging Framework
Extensibility
Processing Model
Protocol Bindings
HTTP Binding
RPC and Encoding
SOAP Styles
Summary

Introduction

It seems like just yesterday SOAP wasn't more than a cleaning product. Now most developers can't hear the word without seeing angle brackets. SOAP originally stood for "Simple Object Access Protocol". If you had asked anyone what SOAP meant several years ago, they would have probably said something like "it's for making DCOM and Corba (e.g., RPC calls) work over the Internet". The original authors admit they were focused on "accessing objects" back then, but over time it became desirable for SOAP to serve a much broader audience. Hence, the focus of the specification quickly moved away from objects towards a generalized XML messaging framework.

The shift in focus creates a slight problem with the "O" in the SOAP acronym. Interestingly, the SOAP 1.2 Working Group has (so far) kept the SOAP name (it's so popular, how could they not?) but decided against spelling it out to avoid misleading developers. Today's official definition, found in the most recent SOAP 1.2 specification, doesn't even mention objects:

SOAP is a lightweight protocol intended for exchanging structured information in a decentralized, distributed environment. SOAP uses XML technologies to define an extensible messaging framework, which provides a message construct that can be exchanged over a variety of underlying protocols. The framework has been designed to be independent of any particular programming model and other implementation specific semantics.

This definition really gets to the heart of what SOAP is about today. SOAP defines a way to move XML messages from point A to point B (see Figure 1). It does this by providing an XML-based messaging framework that is 1) extensible, 2) usable over a variety of underlying networking protocols, and 3) independent of programming models. Let's discuss each of these three characteristics in a bit more detail.

Figure 1. Simple SOAP messaging

First, SOAP extensibility is key. When the acronym stood for something, "S" meant "Simple". If there's one thing we've learned from the Web, it's that simplicity always wins over efficiency or technical purity, and when interoperability is at stake, it's an absolute requirement. Simplicity remains one of SOAP's primary design goals as evidenced by SOAP's lack of various distributed system features such as security, routing, and reliability to name a few. SOAP defines a communication framework that allows for such features to be added down the road as layered extensions. Microsoft, IBM, and other software vendors are actively working on a common suite of SOAP extensions that will add many of these features that most developers expect. The initiative is referred to as the Global XML Web Services Architecture (GXA). Microsoft has already released a reference implementation of several GXA specifications and called it the Web Services Enhancements 1.0 SP1 for Microsoft .NET (WSE).

Second, SOAP can be used over any transport protocol such as TCP, HTTP, SMTP, or even MSMQ (see Figure 1). In order to maintain interoperability, however, standard protocol bindings need to be defined that outline the rules for each environment. The SOAP specification provides a flexible framework for defining arbitrary protocol bindings and provides an explicit binding today for HTTP since it's so widely used.

Third, SOAP allows for any programming model and is not tied to RPC. Most developers immediately equate SOAP to making RPC calls on distributed objects (since it was originally about "accessing objects") when in fact, the fundamental SOAP model is more akin to traditional messaging systems like MSMQ. SOAP defines a model for processing individual, one-way messages. You can combine multiple messages into an overall message exchange. Figure 1 illustrates a simple one-way message where the sender doesn't receive a response. The receiver could, however, send a response back to the sender (see Figure 2). SOAP allows for any number of message exchange patterns (MEPs), of which request/response is just one. Other examples include solicit/reponse (the reverse of request/reponse), notifications, and long running peer-to-peer conversations.

Figure 2. Request/response message exchange pattern

Developers often confuse request/response with RPC when they're actually quite different. RPC uses request/response, but request/response isn't necessarily RPC. RPC is a programming model that allows developers to work with method calls. RPC requires a translation of the method signature into SOAP messsages. Due to the popularity of RPC, SOAP outlines a convention for using RPC with SOAP (see the RPC and Encoding section later in this article).

Armed with these three major characteristics, the SOAP messaging framework facilitates exchanging XML messages in heterogeneous environments where interoperability has long been a challenge.

SOAP Versions

From the first published SOAP specification to today's widely implemented SOAP 1.1, many things have changed, from minor details to major shifts in thinking. SOAP 1.1 was submitted to the W3C and published as a Note back in May 2000. The "W3C Note" status makes SOAP 1.1 little more than a good idea since it didn't go through the rigors of the W3C process, where it would finally reach "Recommendation" status upon completion. Nevertheless, because it's so widely supported by both large and small vendors today, SOAP 1.1 is still considered the de facto standard.

The W3C used the SOAP 1.1 Note as the seed for a new XML Protocol Working Group responsible for producing the next version of SOAP, currently named SOAP 1.2. SOAP 1.2 is currently a "Candidate Recommendation", which means it's in the implementation stage and not far from completion. Once SOAP 1.2 becomes a "Recommendation", it will likely quickly gain vendor support.

After SOAP 1.2 ships, vendors should continue to support SOAP 1.1 for backwards compatibility. SOAP versioning is based on XML namespaces. SOAP 1.1 is identified by the https://schemas.xmlsoap.org/soap/envelope/ namespace while SOAP 1.2 is identified by the http://www.w3.org/2002/12/soap-envelope namespace (although this will change when it becomes a Recommendation).

See Table 1 for a quick reference to each version's namespace name and specification location. Throughout the rest of this article we'll cover the most important areas of SOAP 1.1. Check out the current SOAP 1.2 specification for an extensive list of changes between the two versions.

Table 1. SOAP Version Information

SOAP 1.1  
Namespace Name https://schemas.xmlsoap.org/soap/envelope/
Spec Location http://www.w3.org/TR/SOAP/
SOAP 1.2  
Namespace Name http://www.w3.org/2002/12/soap-envelope
Spec Location http://www.w3.org/TR/soap12-part0/ (Primer)

http://www.w3.org/TR/soap12-part1/

http://www.w3.org/TR/soap12-part2/

Messaging Framework

The core section of the SOAP specification is the messaging framework. The SOAP messaging framework defines a suite of XML elements for "packaging" arbitrary XML messages for transport between systems.

The framework consists of the following core XML elements: Envelope, Header, Body, and Fault, all of which are from the https://schemas.xmlsoap.org/soap/envelope/ namespace in SOAP 1.1. I've provided the full XML Schema definition for SOAP 1.1 in the following code for your reference as you read through the remainder of this section. Personally, I find it helpful to inspect the schema whenever familiarizing myself with XML constructs.

SOAP 1.1 XML Schema Definition

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"        
  xmlns:tns="https://schemas.xmlsoap.org/soap/envelope/"         
  targetNamespace="https://schemas.xmlsoap.org/soap/envelope/" 
>
     
  <!-- Envelope, header and body -->
  <xs:element name="Envelope" type="tns:Envelope" />
  <xs:complexType name="Envelope" >
    <xs:sequence>
      <xs:element ref="tns:Header" minOccurs="0" />
      <xs:element ref="tns:Body" minOccurs="1" />
      <xs:any namespace="##other" minOccurs="0" 
       maxOccurs="unbounded" processContents="lax" />
    </xs:sequence>
    <xs:anyAttribute namespace="##other" 
     processContents="lax" />
  </xs:complexType>

  <xs:element name="Header" type="tns:Header" />
  <xs:complexType name="Header" >
    <xs:sequence>
      <xs:any namespace="##other" minOccurs="0" 
       maxOccurs="unbounded" processContents="lax" />
    </xs:sequence>
    <xs:anyAttribute namespace="##other" 
     processContents="lax" />
  </xs:complexType>
  
  <xs:element name="Body" type="tns:Body" />
  <xs:complexType name="Body" >
    <xs:sequence>
      <xs:any namespace="##any" minOccurs="0" 
       maxOccurs="unbounded" processContents="lax" />
    </xs:sequence>
    <xs:anyAttribute namespace="##any" 
     processContents="lax" />
  </xs:complexType>

       
  <!-- Global Attributes -->
  <xs:attribute name="mustUnderstand" default="0" >   
     <xs:simpleType>
     <xs:restriction base='xs:boolean'>
      <xs:pattern value='0|1' />
    </xs:restriction>
   </xs:simpleType>
  </xs:attribute>
  <xs:attribute name="actor" type="xs:anyURI" />

  <xs:simpleType name="encodingStyle" >
    <xs:list itemType="xs:anyURI" />
  </xs:simpleType>

  <xs:attribute name="encodingStyle" 
   type="tns:encodingStyle" />
  <xs:attributeGroup name="encodingStyle" >
    <xs:attribute ref="tns:encodingStyle" />
  </xs:attributeGroup>

  <xs:element name="Fault" type="tns:Fault" />
  <xs:complexType name="Fault" final="extension" >
    <xs:sequence>
      <xs:element name="faultcode" type="xs:QName" />
      <xs:element name="faultstring" type="xs:string" />
      <xs:element name="faultactor" type="xs:anyURI" 
       minOccurs="0" />
      <xs:element name="detail" type="tns:detail" 
       minOccurs="0" />      
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="detail">
    <xs:sequence>
      <xs:any namespace="##any" minOccurs="0" 
       maxOccurs="unbounded" processContents="lax" />
    </xs:sequence>
    <xs:anyAttribute namespace="##any" 
     processContents="lax" /> 
  </xs:complexType>

</xs:schema>

If you check out the complexType definition for Envelope, you can quickly learn how these elements relate to each other. The following message template illustrates the structure of a SOAP Envelope:

<soap:Envelope
   xmlns:soap="https://schemas.xmlsoap.org/soap/envelope/">
  <soap:Header> <!-- optional -->
    <!-- header blocks go here... -->
  </soap:Header>
  <soap:Body>
    <!-- payload or Fault element goes here... --> 
  </soap:Body>
</soap:Envelope>

The Envelope element is always the root element of a SOAP message. This makes it easy for applications to identify "SOAP messages" by simply looking at the name of the root element. Applications can also determine the version of SOAP being used by inspecting the Envelope element's namespace name.

The Envelope element contains an optional Header element (see the Extensibility section for more information) followed by a mandatory Body element. The Body element represents the message payload. The Body element is a generic container in that it can contain any number of elements from any namespace. This is ultimately where the data goes that you're trying to send.

For example, the following SOAP message represents a request to transfer funds between bank accounts:

<soap:Envelope
 xmlns:soap="https://schemas.xmlsoap.org/soap/envelope/">
 <soap:Body>
  <x:TransferFunds xmlns:x="urn:examples-org:banking">
   <from>22-342439</from>
   <to>98-283843</to>
   <amount>100.00</amount>
  </x:TransferFunds>
 </soap:Body>
</soap:Envelope>

If the receiver supports request/response and it is able to process the message successfully, it would send another SOAP message back to the initial sender. In this case, the response information would also be contained in the Body element as illustrated in this example:

<soap:Envelope
 xmlns:soap="https://schemas.xmlsoap.org/soap/envelope/">
 <soap:Body>
  <x:TransferFundsResponse
   xmlns:x="urn:examples-org:banking">
   <balances>
    <account>
     <id>22-342439</id>
     <balance>33.45</balance>
    </account>
    <account>
     <id>98-283843</id>
     <balance>932.73</balance>
    </account>
   </balances>
  </x:TransferFundsResponse>
 </soap:Body>
</soap:Envelope>

The messaging framework also defines an element named Fault for representing errors within the Body element when things go wrong. This is essential because without a standard error representation, every application would have to invent their own making it impossible for generic infrastructure to distinguish between success and failure. The following sample SOAP message contains a Fault element that indicates an "Insufficient Funds" error occurred while processing the request:

<soap:Envelope
  xmlns:soap="https://schemas.xmlsoap.org/soap/envelope/">
 <soap:Body>
  <soap:Fault>
   <faultcode>soap:Server</faultcode>
   <faultstring>Insufficient funds</faultstring>
   <detail>
    <x:TransferError xmlns:x="urn:examples-org:banking">
     <sourceAccount>22-342439</sourceAccount>
     <transferAmount>100.00</transferAmount>
     <currentBalance>89.23</currentBalance>
    </x:TransferError>
   </detail>
  </x:TransferFunds>
 </soap:Body>
</soap:Envelope>

The Fault element must contain a faultcode followed by a faultstring element. The faultcode element classifies the error using a namespace-qualified name, while the faultstring element provides a human readable explanation of the error (similar to how HTTP works). Table 2 provides brief descriptions of the SOAP 1.1 defined fault codes (all of which are in the https://schemas.xmlsoap.org/soap/envelope/ namespace).

The Fault element may also contain a detail element for providing details about the error, which may help clients diagnose the problem, especially in the case of Client and Server fault codes.

Table 2. SOAP 1.1 Fault Codes

Name Meaning
VersionMismatch The processing party found an invalid namespace for the SOAP Envelope element.
MustUnderstand An immediate child element of the SOAP Header element that was either not understood or not obeyed by the processing party contained a SOAP mustUnderstand attribute with a value of "1".
Client The Client class of errors indicates that the message was incorrectly formed or did not contain the appropriate information in order to succeed. It is generally an indication that the message should not be resent without change.
Server The Server class of errors indicates that the message could not be processed for reasons not directly attributable to the contents of the message, but rather to the processing of the message. For example, processing could include communicating with an upstream processor, which didn't respond. The message may succeed if re-sent at a later point in time.

Now imagine that you want to add some authentication information to the original message so the receiver can determine whether the sender has sufficient rights to execute the transfer. A way to do this would be to add the credentials information into the body as shown here:

<soap:Envelope
 xmlns:soap="https://schemas.xmlsoap.org/soap/envelope/">
 <soap:Body>
  <x:TransferFunds xmlns:x="urn:examples-org:banking">
   <from>22-342439</from>
   <to>98-283843</to>
   <amount>100.00</amount>
   <!-- security credentials -->
   <credentials>
    <username>dave</username>
    <password>evad</password>
   </credentials>
  </x:TransferFunds>
 </soap:Body>
</soap:Envelope>

Going down this path requires every operation that needs authentication to deal with the credentials. It also means that other applications in need of security must develop their own solutions to the problem; ultimately, interoperability suffers. For common needs such as security, it makes more sense to define standard SOAP headers that everyone agrees on. Then, vendors can build support for the extended functionality into their generic SOAP infrastructure and everyone wins. This approach increases developer productivity and helps ensure higher levels of interoperability at the same time. This is exactly the type of thing the SOAP extensibility model was designed to facilitate.

Extensibility

Most existing protocols make a distinction between control information (e.g., headers) and message payload. SOAP is no different in this regard. The SOAP Header and Body elements provide the same distinction in the easy-to-process world of XML. Besides ease of use, the key benefit of the extensible Envelope is that it can be used with any communications protocol.

Headers have always played an important role in application protocols, like HTTP, SMTP, etc., because they allow the applications on both ends of the wire to negotiate the behavior of the supported commands. Although the SOAP specification itself doesn't define any built-in headers, headers will eventually play an equally important role in SOAP. As GXA matures and SOAP headers become standardized, it will become easier for developers to define rich application protocols, without having to reinvent the wheel each time.

The Header element, like the Body element, is a generic container for control information. It may contain any number of elements from any namespace (other than the SOAP namespace). Elements placed in the Header element are referred to as header blocks. As with other protocols, header blocks should contain information that influences payload processing. Hence, this is the right place to put something like a credentials element that helps control access to the operation:

<soap:Envelope
 xmlns:soap="https://schemas.xmlsoap.org/soap/envelope/">
 <soap:Header>
  <!-- security credentials -->
  <s:credentials xmlns:s="urn:examples-org:security">
   <username>dave</username>
   <password>evad</password>
  </s:credentials>
 </soap:Header>
 <soap:Body>
  <x:TransferFunds xmlns:x="urn:examples-org:banking">
   <from>22-342439</from>
   <to>98-283843</to>
   <amount>100.00</amount>
  </x:TransferFunds>
 </soap:Body>
</soap:Envelope>

Header blocks can also be annotated with a global SOAP attribute named mustUnderstand to indicate whether or not the receiver is required to understand the header before processing the message. The following example illustrates how to require the processing of the credentials header:

<soap:Envelope
 xmlns:soap="https://schemas.xmlsoap.org/soap/envelope/">
 <soap:Header>
  <!-- security credentials -->
  <s:credentials xmlns:s="urn:examples-org:security"
   soap:mustUnderstand="1"
  >
   <username>dave</username>
   <password>evad</password>
  </s:credentials>
 </soap:Header>
 ...

If a header block is annotated with mustUnderstand="1" and the receiver wasn't designed to support the given header, the message shouldn't be processed and a Fault should be returned to the sender (with a soap:MustUnderstand status code). When mustUnderstand="0" or the mustUnderstand attribute isn't present, the receiver can ignore those headers and continue processing. The mustUnderstand attribute plays a central role in the overall SOAP processing model.

Processing Model

SOAP defines a processing model that outlines rules for processing a SOAP message as it travels from a SOAP sender to a SOAP receiver. Figure 1 illustrates the simplest SOAP messaging scenario, where there's one application (SOAP sender) sending a SOAP message to another application (SOAP receiver).

The processing model, however, allows for more interesting architectures like the one in Figure 3, which contains multiple intermediary nodes. For the rest of this discussion, I'll use the term SOAP node to refer to any application that processes SOAP messages, whether it's the initial sender, an intermediary, or the ultimate receiver; otherwise I'll be explicit and use the precise term.

Figure 3. Sophisticated SOAP messaging

An intermediary sits between the initial sender and the ultimate receiver and intercepts SOAP messages. An intermediary acts as both a SOAP sender and a SOAP receiver at the same time. Intermediary nodes make it possible to design some interesting and flexible networking architectures that can be influenced by message content. SOAP routing is a good example of something that heavily leverages SOAP intermediaries (for more information on SOAP routing check out Routing SOAP Messages with Web Services Enhancements 1.0).

While processing a message, a SOAP node assumes one or more roles that influence how SOAP headers are processed. Roles are given unique names (in the form of URIs) so they can be identified during processing. When a SOAP node receives a message for processing, it must first determine what roles it will assume. It may inspect the SOAP message to help make this determination.

Once it determines the roles in which it will act, the SOAP node must then process all mandatory headers (marked mustUnderstand="1") targeted at one of its roles. The SOAP node may also choose to process any optional headers (marked mustUnderstand="0") targeted at one of its roles.

SOAP 1.1 only defines a single role named https://schemas.xmlsoap.org/soap/actor/next (next, for short). Every SOAP node is required to assume the next role. Hence, when a SOAP message arrives at any given SOAP node, the node must process all mandatory headers targeted at the next role, and it may choose to process optional headers also targeted at the next role. In addition to next, SOAP 1.2 defines a few more roles (see Table 3) and applications are allowed to define custom roles as well.

SOAP headers target specific roles through the global actor attribute (the attribute is named role in SOAP 1.2). If the actor attribute isn't present, the header is targeted at the ultimate receiver by default. The following SOAP message illustrates how to use actor:

<soap:Envelope 
  xmlns:soap="https://schemas.xmlsoap.org/soap/envelope/">
  <soap:Header>
    <wsrp:path xmlns:wsrp="https://schemas.xmlsoap.org/rp"
    soap:actor="https://schemas.xmlsoap.org/soap/actor/next"
    soap:mustUnderstand="1"
    >
    ...

Since the wsrp:path header is targeted at the next role and marked as mandatory (mustUnderstand="1"), the first SOAP node to receive this message is required to process it according to the header block's specification, in this case WS-Routing. If the SOAP node wasn't designed to understand a mandatory header targeted at one of its role, it is required to generate a SOAP fault, with a soap:MustUnderstand status code, and discontinue processing. The SOAP Fault element provides the faultactor child element to specify who caused the fault to happen within the message path. The value of the faultactor attribute is a URI that identifies the SOAP node that caused the fault.

If a SOAP node successfully processes a header, it's required to remove the header from the message. SOAP nodes are allowed to reinsert headers, but doing so changes the contract parties—it's now between the current node and the next node the header targets. If the SOAP node happens to be the ultimate receiver, it must also process the SOAP body.

Table 3. SOAP 1.2 Roles

SOAP Role Name Description
http://www.w3.org/2002/06/soap-envelope/role/next Each SOAP intermediary and the ultimate SOAP receiver MUST act in this role and MAY additionally assume zero or more other SOAP roles.
http://www.w3.org/2002/06/soap-envelope/role/none SOAP nodes MUST NOT act in this role.
http://www.w3.org/2002/06/soap-envelope/role/ultimateReceiver To establish itself as an ultimate SOAP receiver, a SOAP node MUST act in this role. SOAP intermediaries MUST NOT act in this role.

Protocol Bindings

An interesting aspect of Figure 3 is that SOAP enables message exchange over a variety of underlying protocols. Since the SOAP messaging framework is independent of the underlying protocol, each intermediary could choose to use a different communications protocol without affecting the SOAP message. Standard protocol bindings are necessary, however, to ensure high levels of interoperability across SOAP applications and infrastructure.

A concrete protocol binding defines exactly how SOAP messages should be transmitted with a given protocol. In other words, it defines the details of how SOAP fits within the scope of another protocol, which probably has a messaging framework of its own along with a variety of headers. What the protocol binding actually defines depends a great deal on the protocol's capabilities and options. For example, a protocol binding for TCP would look much different than one for MSMQ or another for SMTP.

The SOAP 1.1 specification only codifies a protocol binding for HTTP, due to its wide use. SOAP has been used with protocols other than HTTP but the implementations weren't following a standardized binding. There's nothing wrong with forging ahead without standard protocol bindings in place as long as you're prepared to deal with interoperability issues once you try to integrate with other SOAP implementations using the same protocol.

HTTP Binding

The HTTP protocol binding defines the rules for using SOAP over HTTP. SOAP request/response maps naturally to the HTTP request/response model. Figure 4 illustrates many of the SOAP HTTP binding details.

Figure 4. SOAP HTTP binding

The Content-Type header for both HTTP request and response messages must be set to text/xml (application/soap+xml in SOAP 1.2). As for the request message, it must use POST for the verb and the URI should identify the SOAP processor. The SOAP specification also defines a new HTTP header called SOAPAction, which must be present in all SOAP HTTP requests (even if empty). The SOAPAction header is meant to express the intent of the message. As for the HTTP response, it should use a 200 status code if no errors occurred or 500 if the body contains a SOAP Fault.

RPC and Encoding

Although the SOAP specification has evolved away from objects, it still defines a convention for encapsulating and exchanging RPC calls using the messaging framework described above. Defining a standard way to map RPC calls to SOAP messages makes it possible for infrastructure to automatically translate between method invocations and SOAP messages at runtime, without redesigning the code around the Web services platform.

To make a method call using SOAP, the infrastructure needs the following information:

  1. Endpoint location (URI)
  2. Method name
  3. Parameter names/values
  4. Optional method signature
  5. Optional header data

This information can be conveyed in a variety of ways including type libraries, IDL files, or better yet, WSDL files. The SOAP RPC binding defines how to encapsulate and represent this information within the SOAP body. It does this by first defining how the method signature maps to simple request/response structures, which can then be encoded as XML. The RPC binding states that the method invocation will be modeled as a struct named after the method. The struct will contain an accessor for each [in] or [in/out] parameter, named the same as the parameter names, and in the order defined by the message signature. The method response will also be modeled as a struct. The name of the struct is insignificant although the convention is to use the method name followed by "Response" (e.g., for an add operation, the method response would correspondingly be named addResponse). The response struct contains an accessor for the return value (the name is insignificant in SOAP 1.1 but must be rpc:result in SOAP 1.2) followed by accessors for each [out] or [in/out] parameter.

Let's look at an example. Assume the following C# method signature for an add operation:

double add(ref double x, double y)

According to the RPC binding rules just described, the request struct representing the method invocation would be modeled as follows:

struct add {
  double x;
  double y;
}

While the response struct would look like this:

struct addResponse {
  double result;
  double x;
}

Now the question is: how should these structures map to XML? The SOAP specification defines a set of encoding rules for exactly this purpose. The SOAP encoding rules outline how to map today's most commonly used data structures (like structs and arrays) to a common XML format. According to the SOAP encoding rules, the request struct from above would map to the following XML message (this would be placed in the SOAP body):

<add>
  <x>33</x>
  <y>44</y>
</add>

And the response message to the above request would map to the following XML message (which would go in the response message's body):

<addResponse>
  <result>77</result>
  <x>33</x>
</addResponse>

The SOAP encoding rules were invented around the time that work on XML Schema was just getting under way. Now that XML Schema is done, developers can simply provide literal XML Schema definitions that specify exactly how the request/response messages should be formatted in XML. Because it's been easier to achieve interoperability using XML Schema definitions, most developers have decided to move away from the SOAP encoding rules completely. In fact, as of SOAP 1.2, supporting the SOAP encoding rules is no longer officially required by the spec. Check out The Argument Against SOAP Encoding for a thorough discussion on why you're probably better off avoiding it from this point on.

Although the SOAP RPC binding and encoding rules provide a nice SOAP integration layer for applications that don't want to mess with things like XML Schema or WSDL, they've fallen out of favor with the Web services community at large because they're more prone to interoperability issues.

SOAP Styles

To reiterate, there are two fundamental styles of SOAP messaging today: document and RPC. Document style indicates that the body simply contains an XML document whose format the sender and the receiver must agree upon. RPC style, on the other hand, indicates that the body contains an XML representation of a method call like we just discussed.

There are also two techniques for deciding how to serialize the data into the body: using literal XML Schema definitions and using the SOAP encoding rules. With the former approach, the schema definition literally defines the XML format for the body without ambiguity. With the latter approach, however, the SOAP processor must walk through the various SOAP encoding rules at runtime to determine the proper serialization of the body. This technique is obviously more prone to errors and interoperability issues.

It's most common to use document style with literal schema definitions (known as document/literal) and RPC style with the SOAP encoding rules (known as rpc/encoded). Document/encoded and rpc/literal are possible but they're not common and don't make much sense. Document/literal is the style that most Web services platforms are focusing on as the main use case going forward, and it is the default in the Microsoft® ASP.NET WebMethod framework today.

Summary

SOAP defines a simple and extensible XML messaging framework that can be used over multiple protocols with a variety of different programming models, although the specification codifies how to use SOAP with HTTP and RPC invocations. SOAP also defines a complete processing model that outlines how messages are processed as they travel through a path. Overall, SOAP provides a rich and flexible framework for defining higher-level application protocols that offer increased interoperability in distributed, heterogeneous environments.