An Extensive Examination of Web Services: Part 6
By Scott Mitchell
An Extensive Examination of Web Services Index |
---|
An Extensive Examination of Web Services is a multi-part article series spanning
several months. Listed below are the current "parts," along with a very brief synopsis and the
date published.
|
Introduction

- A SOAP Envelope,
- An optional SOAP Header, and
- A SOAP Body
The diagram to the right graphically illustrates the pieces of a SOAP message and their relationship. The SOAP Envelope
and SOAP Body are both required pieces of the message, and are denoted via the Envelope
and Body
XML elements. For example, the following shows a SOAP-formatted message that requests that the Add
method
be called, specifying the input parameters a
and b
with values 5 and 8.
|
Note that the XML placed in the Body
element depends on the message itself. For request messages, the
Body
contains the method to call and the serialized input parameters. For the response message, the
Body
contains the serialized result of the method call. (For a discussion on how input and output parameters
are serialized into XML, be sure to read Part 5 of this article series.)
In addition to the SOAP Body, the SOAP Envelope can also contain a Header
section. This Header
section can contain bits of information that are periphery to the Web method call itself. For example, a Web service
method might require that those using the Web service send along a username and password, or some other means to authenticate
the request. Google, which provides Web services for use by the public, requires that to use the Web service one must
obtain a free license key first, and that this license key be passed to the Web service method on each invocation.
A perhaps better approach would have been to remove the need for passing the license key as a parameter in the method,
and rather have it passed as a header. (For more information on using Google's Web services, read:
Searching Google Using the Google Web Service.)
In this article we'll examine how to configure a Web service to accept headers and how to programmatically access the contents of headers from a Web service method. We'll then see how to add a header to an outgoing Web service method call from the client!
Working with SOAP Headers
In order to have a Web service accept a SOAP header we need to perform the following three tasks:
- Define a SOAP header class in the Web service project
- Add a public member variable of the SOAP header class created in step (1) to the Web service class
- Add the
SoapHeader
attribute to the Web method(s) that need to be able to programmatically access the value of the header
Once we perform these three steps at the Web service's end, our next task is to configure the client so that it can invoke a Web service method and pass along data for the appropriate SOAP header(s). The first step, as we've discussed in earlier installments of this article series, is to create a proxy class on the client. This will auto-generate the SOAP header class defined in the Web service project and will add a public property to the proxy class through which an instance of the SOAP header can be affixed to outgoing messages.
To actually pass along a populated SOAP header when calling a Web method the client needs to first create an instance of the proxy's SOAP header class, populate its values, and then assign this header class instance to the appropriate proxy class property. Finally, calling one of the Web service's methods will invoke the method, passing along the SOAP header.
If you are a bit confused at this point, it's quite understandable. Over the next few sections we'll look at each of these steps individually and see how everything fits together.
Step 1: Creating a SOAP Header Class
For a Web service method to accept SOAP headers you must first define the structure of the headers by creating an appropriate class. SOAP headers can be very simple, such as a single string, or can be complex classes with a myriad of properties and collections. The properties of the SOAP header class are the bits of information passed in the particular header. Imagine that we wanted to pass along a SOAP header for authentication purposes. For this example imagine we plan on passing along a username and password. Our first task would be to create an appropriate class in the Web service.
The created class needs to be derived from the System.Web.Services.Protocols.SoapHeader
class. The
following class would constitute an appropriate SOAP header for our example, as it derives from the SoapHeader
class and has two string properties: a Username
and Password
.
|
This SOAP header class needs to be added to the Web service project. You can either add it in the .asmx
file's code section, by adding it as a class after the Web service class itself, or, if you are using Visual Studio .NET,
you can add a new class to the Web service project. For this latter step, right click on the project name and opt to add
a new class. Name the class, AuthenticationSoapHeader.cs
, or something appropriate, and then add the
above code to the class.
Note that the properties in the SOAP header class that you wish to be exposed must be made public or must be created as public get/set property accessors. As we'll see shortly, when calling a Web service method and passing a SOAP header, the values of the SOAP header are serialized into XML just like the input and output parameters of a Web method. (Recall from Part 5 that only public fields or properties are serialized via XML serialization.)
Step 2: Creating an Instance of the Header Class in the Web Service Class
Once you have spelled out the class for the SOAP header, the next step is to add a public member variable to the Web service class of this SOAP header class created in the previous section. Adding a public member variable to the Web service is vital because it allows a means by which the client calling the Web method will be able to affix a SOAP header to the Web service call. The following code shows the Web service class with the added public member variable of type
AuthenticationHeader
:
|
Step 3: Adding the SoapHeader
Attribute to Those Web Methods That Accept the Header
In order for a Web method to be able to accept and programmatically access a SOAP header, you need to add the
SoapHeader
attribute before the Web method declaration. In the SoapHeader
attribute simply
specify the member variable name of the SOAP header chosen in step (2). For example, imagine we had a Web method
called, GetMessage()
, which returned a secret message if the person was authorized to see the message, else
an error string is returned. This method's code might look like:
|
To allow this method to accept a SOAP header we need to add the SoapHeader
attribute like so:
|
Notice that the string passed into the SoapHeader
attribute is the member variable name added in step (2).
With this SoapHeader
attribute addition, GetMessage()
can directly access the properties of
AuthHeader
in its code. For example, if we wanted to limit access to only a single user, one with username
scott
and password password
, we could use:
|
Configuring the Client to Send Along a SOAP Header Value
At this point we have examined the necessary steps for configuring the Web service to accept headers, but we've yet to examine how the client can send a SOAP header along with its call to a particular Web method. The first step is to create a proxy class for the client. (If you have already created a proxy class, then added a SOAP header to the Web service, you'll need to update the client's proxy class. This can be done in Visual Studio .NET by right clicking on the Web Reference and choosing the Update Web Reference option.)
Creating (or updating) the proxy class will auto-generate the SOAP header class in the client's proxy. It will also
add a new property to the Web service named AuthHeaderValue
. In order to send a SOAP header to the
Web service method, the client should do the following:
- Create an instance of the proxy class,
- Create an instance of the SOAP header class and populate its values,
- Affix the SOAP header to the proxy class by assigning the SOAP header class instance created in step (2) to the
proxy class's
AuthHeaderValue
property, and, finally - Call the Web service method
The following code illustrates these four steps. The GetMessage()
Web method is invoked from the client
passing along a username/password pair of scott and password.
|
The value returned from GetMessage()
will contain the appropriate message, based on the username/password
sent via the SOAP header.
Examining the SOAP Message
The values of SOAP headers are placed in the
Header
element of the SOAP message. The .NET Framework
uses XML serialization to serialize the header into XML. This serialized XML is then inserted into the Header
element.
The syntax below shows the SOAP message going from the client to the Web service when invoking the GetMessage()
method with the username/password combination of scott and password.
|
The Web service, upon receiving this SOAP request, automatically deserializes the SOAP header XML into the member variable
instance specified in the Web method's SoapHeader
attribute.
Conclusion and Closing Comments
In this sixth installment of this article series we examined how to use SOAP headers to pass along information periphery to the Web method call itself. Realize that we could have just as well passed the username and password as input parameters to the Web method. However, since this information is secondary to the functioning of the method, it is a cleaner approach to use headers. As we'll see in upcoming portions of this article series, SOAP headers can be used to pass along metadata that allows for common business tasks like:
- Encryption
- Authentication
- Routing
- Transaction management
- And many others!
One final word before signing off - realize that the technique presented in this article for passing authentication information is inherently insecure since the username and password are passed along in plain-text. That is, a nefarious hacker monitoring the network traffic could see the username and password sent along to the Web service. A better approach is to use a one-way hash function to encrypt the password. We'll see how this can be done with little work, and even less code, in a future article installment!
Happy Programming!
|