SOAP, .NET, and COM an Introduction - Part II

The SOAP XML Object Model

SOAP itself does not handle objects. In fact, the object in "simple object access protocol" lends itself simply to the formation of a outstanding name. Actually, SOAP was intended for RPC use and designed to convert a method's parameters from its native binary form and carry those parameters to the remote server as XML information. After that, the XML information would be pulled by a corresponding SOAP processor and returned to its binary state for processing. Information that associates the method with some object (C++, Java, SmallTalk, or whatever) would be metadata to SOAP and would have to be encoded separately from the method itself.
However, SOAP does have an object model in a sense. SOAP is XML, as defined by an XSD schema, so it really consists of XML elements. However, you can think of these elements in terms of objects, with each object having a distinct purpose. In that light, the SOAP object model consists of three main objects:

  • The SOAP Envelope
  • The SOAP Header
  • The SOAP Body

The root document element of the SOAP XML packet is formed by the SOAP Envelope. To convey the XML namespace information used is one of its primary jobs when the packet was serialized. Since the Envelope is the XML root document element, the other two SOAP objects (also XML) need to be serialized within the Envelope. Another important task is to encapsulate the SOAP information for any given SOAP RPC invocation.

The SOAP Header is an optional piece of the object model. To process the request that is not found in the method's signature, it carries information necessary. You can generally find public key encryption information, transactional sequence identifiers, information needed by the various actors processing the message, and other metadata that the remote SOAP processor may require to manage the remote request.

The real action takes place in the SOAP Body. Since here, you find the method and its parameters stored as XML. The remote SOAP processor rips through the SOAP Body and converts the XML parameter information back to a native format for processing. In this article, we would like to discuss the SOAP Body and the formatting of various method parameters and constructs.

After this brief introduction, let us look at the objects themselves in more detail, starting with the SOAP Data Types and than Envelopes.

SOAP Data Types

In Web services, SOAP Data types are important part. To translate from the native language of a software application to the SOAP protocols that move the request over the wire SOAP uses serializer and deserializer objects. In this part native languages introduce dependencies on the data. For example, Java defines date objects in a different way than Microsoft .NET C++ date objects. This has an adverse effect, SOAP data types with the same name can have different implementations. This causes interoperability problems.

Floating-point numbers and dates are data types that most commonly fail interoperability analysis.

Floating-point and decimal data types

Floating-point numbers in SOAP are represented as strings of decimal digits. The SOAP definition for floating point numbers also allows the possibility to handle exponential numbers using notation in use by engineers for decades. In general, this works as would be expected. However, when pushed floating-point numbers have problems.
For example, the original IBM SOAP4J implementation (now the Apache SOAP and Apache AXIS libraries) used the Java toString method and constructor to convert floating-point values found in SOAP documents into Java objects. Numbers appear as a series of decimal numbers. When it came to serializing the floating-point number, "infinity" Java outputs the string as "Infinity". On the other hand, XML Schema serializes infinity as "INF." This caused SOAP4J to have interoperability problems with other SOAP toolkits.

Just as the Internet was born from the cooperation of network administrators, today we see SOAP implementers cooperating to solve interoperability problems. Apache SOAP, the successor to SOAP4J, was changed to accept "INF" as a valid way to serialize infinity.

Decimal data types suffer from language dependencies when pushed too. Decimal data types may represent large numbers up to 40 digits of precision. Relying on all 40 digits in a SOAP request or response is problematic unless both server and client are implemented on the same language. This is also true for fractional seconds with dates and trailing zeros on decimals.

BigDecimal is a good example of interoperability problems introduced by language dependencies. Decimal numbers are a used widely for financial calculations in banking applications where huge numbers are required. The XML Schema specification for decimal data types allows an arbitrary precision. Decimal data types could represent 1000 digits of precision that is a decimal number represented as a string of 1000 one-digit numbers. Apache SOAP is based on the Java implementation of the BigDecimal data type. Java's BigDecimal has an upper limit to precision of a number depending on the underlying operating system (Solaris, Windows, etc.).

XML Schema can solve these sorts of interoperability problems by defining a minimally conforming implementation specification. XML Schema requires at least 18 digits of precision in the case of decimal data types. Apache and Java can meet this requirement. However, that does not mean SOAP-based Web service will receive the minimum precision.

Microsoft .NET implementations can manage BigDecimal data types up to 29 digits of precision. If there are extra digits when an Apache SOAP request with a BigDecimal data type receives a .NET response, unfortunately, it rests with the local SOAP serializer and deserializer implementation to know. In this case, the SOAP transaction is valid but the data is wrong. Developers need to consider the invalid data from a SOAP exchange and should code data tests and protections into their software applications.

Primitive Types

  • string, boolean, decimal, float, double, duration, dateTime, time, date, gYearMonth, gYear, gMonthDay, gDay, gMonth, hexBinary, base64Binary, anyURI, QName, NOTATION

Derived Types

  • Simple types (derived from a single primitive type)
  • integer is derived from decimal
  • int (-2147483648 <= int <= 2147483647) is derived from long which is derived from integer 
  •  5-digit zip code can be derived from int
  • may use regular expressions to specify derived types, such as ([A-Z]){2,3}-\d{5}
  • Complex types (struct or array)
  • person's contact information

SOAP Envelope

The Envelope must be the first element in a SOAP message. It identifies an XML document as being a SOAP message and encapsulates all the other parts of a message. The Envelope contains the version information about the message, and it identifies the rules used by the application to serialize data. Both the version and encoding rules are represented as namespace URIs in the Envelope.

In an XML document, the SOAP envelope is the most important element that represents the SOAP message. XML namespaces are used to disambiguate SOAP identifiers from application specific identifiers. They are used a great deal in SOAP to qualify or scope elements in the message to a specific domain. It helps to be familiar with the namespace spec for XML to understand SOAP namespaces. If you do not have this knowledge, you can simply think of namespaces as neighborhood identifiers that help exclusively identify SOAP elements by associating them with real or imagined specific locations.

A SOAP message is an XML document that consists of a fixed SOAP envelope, an optional SOAP header, and a mandatory SOAP body as the following: The Envelope is the top element of the XML document representing the message. The Header is a generic mechanism for adding features to a SOAP message without prior agreement between the communicating parties. SOAP defines a few attributes that can be used to indicate some extra information.

<SOAP-ENV:Envelope
xmlns
:SOAP-ENV=http://schemas.xmlsoap.org/soap/envelope/
SOAP-ENV:
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<
SOAP-ENV:Header>
<
t:Transaction xmlns:t="some-URI">
SOAP-ENV:mustUnderstand="1"
</t:Transaction>
</
SOAP-ENV:Header>
<
SOAP-ENV:Body>
<
m:GetLastTradePrice xmlns:m="some-URI">
<
symbol>AOL</Symbol>
</
m: GetLastTradePrice>
</
SOAP-ENV:Body>
</
SOAP-Envelope>

Or another example

<SOAP:Envelope
xmlns:SOAP=http://schemas.xmlsoap.org/soap/envelope/
SOAP-ENV:
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/>
<
SOAP:Body>
<
m:getStateName xmlns:m="http://www.ets-software.com/">
<
statenum>6</statenum>
<
format>abbreviation</format>
</
m:getStateName>
</
SOAP:Body>
</
SOAP:Envelope>

In the first example, a GetLastTradePrice request is being sent to a stock-quote service somewhere on the Web. The request takes a string parameter, a ticker symbol, and returns a float in the SOAP response.
In this example, the first namespace references the SOAP schema. It defines the elements and attributes in the SOAP message. The second namespace refers to SOAP encodings.. This encoding applies to the whole document since no additional per-element encoding is specified.

The SOAP Header

The first element identified in the previous sample SOAP envelope header is a transaction element. It is accompanied by a namespace attribute and by the mustUnderstand attribute with a value of 1. The server accepting this message must perform intermediate processing on this transaction node since mustUnderstand is set to 1.This means, upon the semantics that govern the processing of this header element, the server and client have previously agreed, therefore the server knows exactly what to do with the contents of the element, in this case 5.

It is required to reject the request completely and throw a fault if the server receiving this message does not understand the semantics of the transaction header. A fault element is a unique part of the SOAP body and a well-defined instrument to ship error information back to the client. Intermediate processing nodes like this are an example of SOAP's extensibility. Clients include such nodes in a SOAP message to indicate that before the contents of the message body can be processed special processing needs to take place. Ensuring backward compatibility with existing servers not capable of providing such processing. This is simply a matter of setting the mustUnderstand attribute to 0, which makes the action optional.

In a given SOAP packet, you might or might not find header information serialized, since the SOAP Header is an optional object. On the other hand, if there is header information, all of that information must be serialized within the SOAP Header object, which must be the first (XML) child of the Envelope element. That is where you will find it, but what is it used for?

Well, briefly, we use the SOAP Header to transmit supplementary information pertinent to the Web Service processing that is not part of the method signature. For instance, suppose that you have a Web Service that specifies the categories and price of the Book that you intend to order in C#:

OrderInfo Orderbook (char [] category, int [] price, PaymentInfo pinf);

For this example, let us assume that the OrderInfo structure has shipping information such as order confirmation, shipping timeline, and so on. The integer array contains integer that enumerate price and char array the various categories available to you. The payment information structure contains payment data, such as a credit card number.

In this case, the Web Service takes your Book order (presumably, to establish your identity and shipping information you called another Web Service before this). However there should be some sort of encryption associated with this invocation, such as the customer, you may want to see at least the payment information, if not the entire packet, encrypted.

Using the encodingStyle attribute, the fact that the payment information is encrypted could be verified. However, you can also include public key information necessary to decrypt the payment data as SOAP Header information. This is the approach that the SOAP Digital Signatures specification uses it. In addition, it can be found at http://www.w3.org/TR/SOAP-dsig/. The Book Web Administrator wants to know that you placed an order. On the other hand, Book-ordering software is concerned with the integrity of the payment information, which is orthogonal to the method signature. That is, decryption keys are essential to the processing of the Book order.

The contents of the header and arrangement are specific to the Web Service. If the information is well formed XML and otherwise adheres to the SOAP specification, using any XML vocabulary, you can put anything in there. Anyone who wants to insert Header information may do so, but it will all use the single SOAP Header XML element. Consequently, within the Header, each child element must be qualified using a namespace. After all, you have to be able to pull the header information back out again. You will need the associated namespace to do that reliably. One example of a very complex SOAP Header can be found in the SOAP Digital Signature specification. Luckily, most header entries are not this complex. Other simpler examples might include these:

  • Transaction IDs
  • Packet sequence values
  • Causality IDs (deadlock prevention)
  • Authentication information
  • Session identification information
  • Message routing information
  • Other Web Service method metadata

This is not an exhaustive list, but it confidently gives you an idea of the types of things that SOAP headers typically convey.

There is one rule to follow according to the SOAP specification; you need to keep the header information self-contained. The XML in the header should not somehow refer to the SOAP Body. This allows SOAP processing software to analyze and without necessarily processing the body to deal with header information. In fact, to allow for more generic services, this rule is sometimes broken. For instance, an important exception to this rule is provided by the SOAP Digital Signature specification. However, if you are encrypting a portion of the body using public key information found in the header, there is a clear need to indicate body contents. Essentially, the header elements should be self-contained, at least within the header element.

A SOAP message may optionally contain header entries specifying nodes that perform authorization-processing, encryption, persistence of state, business logic processing, in addition to defining transaction nodes like the one described. With Headers SOAP is able to make a modular, extensible packaging model. Just keep in mind that header processing is entirely independent of the SOAP message body.

The SOAP Body

he SOAP body in the example contains an XML payload, which we can surmise, without really seeing it spelled out for us, does RPC. Nothing here clearly shows that RPC is being used. All we see in the body are a couple of XML elements, one qualified by a namespace. SOAP server needs to understand the document semantics and do the right thing. In fact, to deal with the XML payload in a significant way the server provides a framework. "Significant" here means that to receive the stock price for the stock-symbol element contained in the message body the server invokes a remote procedure call on some back-end database. All the magic occurs behind the SOAP RPC curtain.

Here is a foreshortened, RPC-based view of the SOAP message presented earlier. Only the body portions of the SOAP request and response envelopes are shown.

<
SOAP-ENV:Body>
<
m:GetLastTradePrice xmlns:m="some-URI">
<
symbol>DEF</Symbol>
</
m:GetLastTradePrice>
</
SOAP-ENV:Body>

Response

<SOAP-ENV:Body>
<
m:GetLastTradePriceResponse xmlns:m="some-URI">
<
price>22.50</price>
</
m: GetLastTradePriceResponse>
</
SOAP-ENV:Body>


Similar Articles