Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

C# ПІДРУЧНИКИ / c# / Hungry Minds - ASP.NET Bible VB.NET & C#

.pdf
Скачиваний:
128
Добавлен:
12.02.2016
Размер:
7.64 Mб
Скачать

Thus, the request/ response RPC-style protocol is a function of HTTP and not of SOAP.

§A definition for a protocol binding between SOAP and HTTP. This describes how SOAP messages are transmitted using HTTP as the transport protocol.

Because the SOAP envelope is the only mandatory part of the specification, let's first take a look at the elements that comprise a SOAP message and their purpose.

SOAP Message Elements

A SOAP message is composed of three primary elements, each of which performs a special purpose. These elements are listed in Table 24-1.

Table 24-1: SOAP message elements

Message Element

Envelope

Description

Serves as a container for the remaining SOAP message elements.

 

Header

 

 

Contains

 

 

 

 

 

optional

 

 

 

 

 

data a

 

 

 

 

 

consumer

 

 

 

 

 

may or may

 

 

 

 

 

not be

 

 

 

 

 

required to

 

 

 

 

 

understand

 

 

 

 

 

to process

 

 

 

 

 

the

 

 

 

 

 

message

 

 

 

 

 

properly.

 

 

 

 

 

This is the

 

 

 

 

 

primary

 

 

 

 

 

extensibility

 

 

 

 

 

mechanism

 

 

 

 

 

of SOAP.

 

 

 

 

 

 

Body

 

 

Contains the

 

 

 

 

 

actual

 

 

 

 

 

encoding of

 

 

 

 

 

a method

 

 

 

 

 

call and any

 

 

 

 

 

input

 

 

 

 

 

arguments

 

 

 

 

 

or an

 

 

 

 

 

encoded

 

 

 

 

 

response

 

 

 

 

 

that

 

 

 

 

 

contains the

 

 

 

 

 

results of

 

 

 

 

 

the method

 

 

 

 

 

call.

 

 

 

 

 

 

The following sections describe each of these elements in more detail.

 

 

The SOAP envelope

The SOAP envelope element is a required part of a SOAP message. It serves as a container for all remaining SOAP message elements. Typically, this includes the SOAP header and body elements. In addition to serving as a container for the header and body elements, the envelope defines the namespaces used by these elements. Figure 24-1 graphically depicts the structure of a complete SOAP message.

Figure 24-1: Structure of a SOAP Message

To deliver a SOAP message to an endpoint, addressing information specific to the transport protocol binding is used as a means to ensure that the message is delivered to the correct endpoint, much like the name and address on a real envelope that is used by a postal authority to deliver the mail. In the case of HTTP, a custom HTTP header named SOAPAction is used to direct the message to the proper endpoint.

One of the major reasons that message addressing is implemented in this manner is that systems administrators can configure firewall software to look for and filter traffic based on this header information, without requiring parsing of the XML.

The following sample code illustrates the format of a SOAP request message envelope:

<soap:Envelope xmlns:xsi="http://www.w3.org/2001/

XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"

xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">

<soap:Body>

<!-- The Soap body elements are inserted here -->

</soap:Body>

</soap:Envelope>

The SOAP envelope is identified by the soap:Envelope element. This particular example contains a soap:Body element, but no soap:Header element. Now that we've briefly described the SOAP envelope, let's discuss SOAP headers.

The SOAP header

The SOAP header element is an optional part of a SOAP message. It defines additional information that can be related to the method request in the body element or, more likely, information that is independent of the method request that is

required or otherwise useful to your application. SOAP does not define the specific contents or semantics for a SOAP header.

SOAP headers are quite similar in concept to the META tags found in HTML documents. They define metadata that can be used to provide context to, or otherwise direct the processing of, the message. The following example shows a SOAP header named Authentication that passes user credentials as part of a Web service method request:

<soap:Envelope xmlns:xsi="http://www.w3.org/2001/

XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"

xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">

<soap:Header>

<Authentication xmlns="http://tempuri.org">

<Username>JDC</Username>

<Password>unknown</Password>

</Authentication>

</soap:Header>

<soap:Body>

<!-- The SOAP body elements are inserted here -->

</soap:Body>

</soap:Envelope>

Each direct child element of the header element is defined as a separate SOAP header. A typical use of SOAP headers is in the area of authentication (as shown in the example), where the credentials required to access the method are encoded in a SOAP header. The implementation code of the method can use the credentials obtained from the SOAP header to invoke an authentication service provided by the underlying platform, rather than having to implement this functionality itself.

If a header element is specified within a SOAP envelope, the header element must be the first element to appear after the opening envelope tag. In addition, SOAP headers (in other words, header subelements) must use XML namespaces to qualify their names, as we did with the Authentication SOAP header example.

SOAP header elements also support an optional MustUnderstand attribute. This attribute accepts a True or False setting, which is used to specify whether or not the message recipient must understand the data within the header. If the MustUnderstand attribute is set to True, the recipient must acknowledge the header by setting the DidUnderstand attribute on the header to True. If this is not done, a SoapHeaderException is generated. We will see examples of this attribute later in this chapter, when we cover the .NET support for SOAP headers.

That's enough about SOAP headers, for now. We'll look at how to use SOAP headers in more detail in an upcoming section. Let's continue our discussion of SOAP message parts by looking at the SOAP body.

The SOAP body

The SOAP body element is a required part of a SOAP message that contains the data specific to a particular method call, such as the method name and any input/output arguments or the return values produced by the method.

The contents of the SOAP body depend on whether the message is a request or a response. A request message contains method call information, whereas a response message contains method call result data.

The following example code illustrates the format of a SOAP body for a request to a temperature conversion method named CTemp:

<soap:Envelope xmlns:xsi="http://www.w3.org/2001/

XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"

xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">

<soap:Body>

<CTemp xmlns="http://tempuri.org/">

<Temperature>32</Temperature>

<FromUnits>F</FromUnits>

<ToUnits>C</ToUnits>

</CTemp>

</soap:Body>

</soap:Envelope>

The sample shows the method name encoded as the CTemp element. Within this element are the encoded input arguments required to call the CTemp method.

The SOAP body for the response message to the CTemp method request is as follows:

<soap:Envelope xmlns:xsi="http://www.w3.org/2001/

XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"

xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">

<soap:Body>

<CTempResponse xmlns="http://tempuri.org/">

<CTempResult>0</CTempResult>

</CTempResponse>

</soap:Body>

</soap:Envelope>

Here we can see that the body of the response message contains a single result element named CTempResult that encodes the numeric result of the temperature conversion. Of course, if the method call were to fail for some reason, the response message would not contain the results we expected, but instead would contain exception (or fault) information describing the error that occurred. We will look at this possibility in the next section.

SOAP Data Type Support

The SOAP specification defines data type support in terms of XSD, the XML Schema specification. This specification defines standards for describing primitive data types as well as complex, hierarchical structures. As you would expect, there is support for integers, strings, floats, and many other primitive types, as well as lists (or arrays) of these primitive types.

In addition to primitive types, user-defined structures can be represented. This is significant, because it paves the way for describing complex, hierarchical data relationships such as what might be found in an invoice or purchase order. The bottom line here is that it is possible to describe any type of data using XSD. Thus, SOAP is capable of supporting any data type, from the built-in primitives defined by XSD all the way to any arbitrary user-defined structure.

This is one of the primary reasons that SOAP is the preferred protocol for exchanging Web service request and response messages, because it enables Web services to accept as well as return any type of data that can be represented by an XSD schema. The Common Language Runtime within .NET provides support for a wide variety of the common data types. All of these data types are shared equally across all of the .NET

languages and also have a well-defined mapping to XSD data types, as shown in Table 24-2.

Table 24-2: XSD data types vs. CLR data types

XML Schema Definition

 

Common

 

 

Language

 

 

Runtime

 

 

 

boolean

 

Boolean

 

 

 

byte

 

N/A

 

 

 

double

 

Double

 

 

 

datatype

 

N/A

 

 

 

decimal

 

Decimal

 

 

 

enumeration

 

Enum

 

 

 

float

 

Single

 

 

 

int

 

Int32

 

 

 

long

 

Int64

 

 

 

Qname

 

XmlQualifiedName

 

 

 

short

 

Int16

 

 

 

string

 

String

 

 

 

timeInstant

 

DateTime

 

 

 

unsignedByte

 

N/A

 

 

 

unsignedInt

 

UInt32

 

 

 

unsignedLong

 

UInt64

 

 

 

unsignedShort

 

UInt16

Note

The CLR specification defines the data types available to all

 

languages. However, not all .NET languages support all of the

 

available data types. For example, Visual Basic.NET does not

 

directly support unsigned Ints. You should refer to your specific

 

CLR language documentation to determine which CLR data types

 

are supported.

In addition to complete primitive data type support, complex structures can be represented within .NET. For example, you can define a structure or class named Invoice that describes the data elements of an invoice document. The .NET Framework and ASP.NET automatically serialize and deserialize these data structures into XMLencoded element hierarchies that can be carried in the SOAP message body. This makes it possible to pass very complex data and data relationships as a single argument to a Web service method!

As you can see, the data type support provided by XSD and SOAP is very powerful and enables the development of potentially complex applications.

Although a great deal of detail and information exists related to data types and structures as defined within XSD and SOAP, there's just not enough time or space to go into it here. What's more, you really don't have to know much about how your Web service parameters or results are serialized into XML because ASP.NET and the .NET Framework classes handle this for you automatically.

Note If you wish to learn more about describing data, you are encouraged to examine the XML Schema Definition and SOAP

The SOAP specification uses the term faults rather than exceptions. I have chosen to use the latter to maintain consistency with the terminology used within the .NET Framework, which refers to SOAP faults as exceptions. This terminology is also reflected in the SOAP classes within .NET.

specifications at the W3C Web site, located at http://www.w3.org. Some reference material related to this subject also is available with the .NET Framework online documentation.

SOAP Exceptions

If Web service methods were guaranteed to work at all times, we would not need any form of error notification or processing capabilities. Unfortunately, things can (and often do) go wrong. As such, errors or exceptions that occur in a Web service method call need to be communicated back to the consumer of the Web service in some manner.

This is where SOAP exceptions come into play. SOAP exceptions are used to return error or exception information to the consumer of a Web service as the result of a failed method call.

Note

SOAP exceptions can occur at various stages of processing a Web service request. For example, an error can occur at the HTTP level before the method call can actually be delivered to the Web service. In this case, an HTTP response must be returned, using the standard HTTP status code numbering conventions.

If the message makes it past the HTTP layer, it must be translated and dispatched to the actual implementation code that executes the method request. If an error occurs here, the server must return a fault message.

The following is an example of a SOAP exception message that returns an applicationdefined exception as the response message:

<soap:Envelope xmlns:xsi="http://www.w3.org/2001/

XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"

xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">

<soap:Body>

<soap:Fault>

<faultcode>400</faultcode>

<faultstring>

Divide by zero error

</faultstring>

<runcode>Maybe</runcode>

<detail>

<t:DivideByZeroException xmlns:t="http://tempuri.org">

<expression>x = 2 / 0;</expression>

</t:DivideByZeroException>

</detail>

</soap:Fault>

</soap:Body>

</soap:Envelope>

As shown in the sample, the exception is contained within the soap:Fault element. The faultcode element specifies the SOAP fault that occurred. Currently, four fault codes are defined, which are listed and described in Table 24-3.

Table 24-3: SOAP fault codes

Value

 

Name

 

Meaning

 

 

 

 

 

100

 

Version

 

The call used an

 

 

Mismatch

 

unsupported SOAP

 

 

 

 

version.

 

 

 

 

 

200

 

Must

 

An XML element

 

 

Understan

 

was received that

 

 

d

 

contained an

 

 

 

 

element with the

 

 

 

 

"mustUnderstand=tr

 

 

 

 

ue" attribute, but

 

 

 

 

was not understood

 

 

 

 

by the receiver.

 

 

 

 

 

300

 

Invalid

 

The receiver did not

 

 

Request

 

process the request

 

 

 

 

because it was

 

 

 

 

malformed or not

 

 

 

 

supported.

 

 

 

 

 

400

 

Application

 

The receiving

 

 

application faulted

 

 

Faulted

 

 

 

 

when processing

 

 

 

 

 

 

 

 

the request. The

 

 

 

 

detail element

 

 

 

 

contains

 

 

 

 

information about

 

 

 

 

the fault.

The faultstring element contains a string description of the error that occurred. The runcode element indicates whether or not the requested operation was performed before the error occurred. This must contain one of either Yes, No, or Maybe.

The detail element is optional and specifies an application-defined exception object (in this case, a DivideByZeroException object).

ASP.NET implements a SoapException class that can be used with the structured exception-handling capabilities built into the CLR to catch SOAP exceptions and handle them using try . . . catch blocks. This means that our ASP.NET applications have a robust, natural mechanism for handling errors within a Web service as well as within a consumer application that is identical to handling any other type of exception within the CLR. We will see specific examples of SOAP exception handling using .NET later in this chapter.

HTTP As a SOAP Transport

To deliver messages encoded as SOAP requests or responses, we need a transport protocol. This transport protocol must be widely available in order to maximize the reach of our Web services. The obvious choice of HTTP as the transport protocol makes SOAP a highly available message format. In addition, the request/response nature of HTTP gives SOAP its RPC-like behavior when piggybacking this transport protocol.

Another advantage of HTTP as the primary transport protocol is that it is humanreadable, just like the SOAP message itself. Figure 24-2 graphically depicts the structure of a SOAP message within the payload section of an HTTP POST request.

Figure 24-2: Structure of a SOAP message contained within an HTTP Post request The POST command contains a request URI that specifies the object endpoint ID. The

server is responsible both for mapping this URI to the implementation of the Web service and for activating the code that is proper for the platform on which it is running.

The SOAP request also must specify which method is to be called. This is done via a custom HTTP header (signified by SoapMethodName) and specifies the namespacequalified method name to be invoked.

Following the HTTP header is the actual payload of the POST request. The payload is always separated from the last header by a single empty line. Now that you have an idea of what a complete SOAP message bound to the HTTP transport looks like, let's look at a specific example. The following sample code shows a complete SOAP request message in the payload section of an HTTP POST request:

POST /ctemp/ctemp.asmx HTTP/1.1

Host: localhost

Content-Type: text/xml; charset=utf-8

Content-Length: length

SOAPAction: "http://tempuri.org/CTemp"

<?xml version="1.0" encoding="utf-8"?>

<soap:Envelope xmlns:xsi="http://www.w3.org/2001/

XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"

xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">

<soap:Body>

<CTemp xmlns="http://tempuri.org/">

<Temperature>32</Temperature>

<FromUnits>F</FromUnits>

<ToUnits>C</ToUnits>

</CTemp>

</soap:Body>

</soap:Envelope>

Notice that the POST request URI specifies the object endpoint ID. This is used by ASP.NET to locate and activate the Web service code. The method call being requested is specified by the HTTP SoapAction header. In this instance, the CTemp method is the requested function to be called. Finally, the body of the SOAP message contains the input arguments to the CTemp method call. In this case, there are three arguments. Similar to the SOAP request message bound to the HTTP POST command, a SOAP response message uses the HTTP response to indicate the results of the method call, as in the following HTTP response example:

HTTP/1.1 200 OK

Content-Type: text/xml; charset=utf-8

Content-Length: length

<?xml version="1.0" encoding="utf-8"?>

<soap:Envelope xmlns:xsi="http://www.w3.org/2001/

XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"

xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">

<soap:Body>

<CTempResponse xmlns="http://tempuri.org/">

<CTempResult>0</CTempResult>

</CTempResponse>

</soap:Body>

</soap:Envelope>

In this example, you can see the result of the CTemp method call returned in the payload section of the HTTP response message. The SOAP rules for encoding the response element use the same name as the call element from the request message with the Response suffix concatenated to it. In this case, this results in a response element named CTempResponse.

Although SOAP does not require HTTP as a transport binding, it is the default and preferred binding for SOAP messages. However, it is also possible to create bindings for SOAP messages over such protocols as SMTP and FTP, although the .NET framework does not yet provide this support by default. For now, ASP.NET Web Services transport SOAP messages exclusively using HTTP.

This brief overview of the SOAP specification hopefully will provide you with enough background to feel comfortable working with SOAP messages when, and if, it's necessary. Of course, if you need more information about SOAP, you should read the SOAP specification available at the W3C Web site located at http://www.w3.org.

Now that you have a basic understanding of SOAP, let's take a look at the SOAP support built into the .NET Framework and how you can leverage this support in building your Web service applications.

SOAP in the .NET Framework

Fortunately, everything that we have discussed related to SOAP up to this point is largely unnecessary with respect to implementing simple ASP.NET Web Services, because ASP.NET and the .NET Framework automatically generate and process SOAP messages for your Web service, leaving you to focus on writing the logic of your Web service application using a familiar object-oriented design approach.

However, more sophisticated Web services may require access to the SOAP messages in order to add custom headers, examine incoming/outgoing SOAP messages, or otherwise alter the default format of messages generated by the .NET XML serializer when interoperating with SOAP message processors on other platforms.

If SOAP message customization becomes necessary for a particular Web service that you wish to implement, the .NET Framework and ASP.NET provide the means to gain access to the SOAP messages so that you can perform the customizations that you need. In this section, we will look at some of the features provided by ASP.NET that you can use to customize the default SOAP message formats and contents.

Using SOAP headers

SOAP headers are the chief extensibility mechanism offered by the SOAP specification. This feature enables you to piggyback metadata along with a method request or response message that can be used by the receiver to control, or add additional context to, the method call.

For example, user credentials are often added as a SOAP header to enable a Web service method to authenticate a user before allowing the method call to be executed. In this example, the SOAP header is added by the consumer application and processed by the Web service method.

The SOAP specification does not define the contents of SOAP headers. The content and semantics associated with a SOAP header are completely defined by the application that adds the header and the recipient that processes it.

ASP.NET Web Services use SOAP as the default protocol for exchanging messages. This makes it possible for applications to add SOAP headers for their own use. Adding SOAP headers to ASP.NET Web Services is as simple as adding a SoapHeader attribute onto a Web service method.

.NET SoapHeader class

The .NET Framework provides a SoapHeader base class (found in the System.Web. Services.Protocols namespace), which we can inherit from to create and use a SOAP header.

An example (drawing on our previous discussion of user credentials and authentication) of a custom SOAP header class is as follows.

VB.NET:

Imports System.Web.Services.Protocols

Public Class AuthenticationSoapHeader

Inherits SoapHeader

Public Username as String

Public Password as String

End Class

C#:

using System.Web.Services.Protocols;

public class AuthenticationSoapHeader : SoapHeader {

public string Username;

public string Password;

}

In this example, we create a class named AuthenticationSoapHeader that inherits from the SoapHeader base class. Within this class are two public member variables named

Соседние файлы в папке c#