In this chapter we explored cross-device application development opportunities. We examined the trials and tribulations inherent in developing cross-device applications as well as some design patterns that ease development stress. We
Cross-device programming is a hot issue for developers today. For those of you who are just beginning to design the
The logical partitioning of your application is a critical factor in code reusability. Just as your business logic should be able to support different types of
Chapter 14
In previous chapters we exposed you to SOAP and showed how you can use it as part of your toolkit of Web Service applications. Because SOAP is a critical component of the .NET Framework and other Web-centric technologies, you should understand not only the syntax and semantics, but also the principles behind it. In this chapter we will go to another level of detail on SOAP—how it works, how messages look, and how you can work directly with them.
In the chapter we will cover the details of the SOAP
<Envelope>,
breaking it down into the
<Header>
,
<Body>
, and encoding
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
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="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/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
SOAP-ENV:encodingStyle
attribute is used to
You can define your own encoding rules. In that case you will need to define your own schema.
Now let's
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
To show you an example of how to use the
<Header>
element, let's make a request to an imaginary language-translation service that
Listing 14-2 soap_header.xml: Some example SOAP <Header> elements.
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/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.
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 . 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="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle=" http://schemas.xmlsoap.org/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.
When a SOAP message
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,
http://schemas.xmlsoap.org/soap/actor/next
, to indicate that the associated
<Header>
element is intended for the first SOAP recipient, intermediary or
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.
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
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 Englishsentence 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="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/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.
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="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/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
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="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/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:
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:
|
|
Client |
The message was incorrectly
|
|
Server |
The message could not be
|
In addition to these standard elements you can include your own custom subelements within the <Fault> element as long as they are namespace-qualified.
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 http://schemas.xmlsoap.org/soap/encoding/
,
is
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, such as integers, strings, and floating-point
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>
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>
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