When you think ASP, think...
Recent Articles
All Articles
ASP.NET Articles
ASPFAQs.com
Message Board
Related Web Technologies
User Tips!
Coding Tips
Search

Sections:
Book Reviews
Sample Chapters
Commonly Asked Message Board Questions
JavaScript Tutorials
MSDN Communities Hub
Official Docs
Security
Stump the SQL Guru!
Web Hosts
XML
Information:
Advertise
Feedback
Author an Article

ASP ASP.NET ASP FAQs Message Board Feedback
 
Print this Page!
Published: Wednesday, December 31, 2003

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.
  • Part 1 - Examines the basics of Web services, what Web services are, and the technologies and standards that serve as the underpinnings of Web services. (October 8th, 2003)
  • Part 2 - Examines creating Web services using Visual Studio .NET. Looks underneath the hood of the code created by VS.NET. (October 15th, 2003)
  • Part 3 - Examines creating a client application that consumes a Web service. Discusses the purpose and structure of a WSDL document, along with creating and using proxy classes to consume a Web service. (November 5th, 2003)
  • Part 4 - Examines the utility of Web services and common scenarios where Web services make sense. A business-oriented look at Web services. (November 19th, 2003)
  • Part 5 - Takes an in-depth look at XML serialization, which is the process of converting a data type, such as an integer, array, or custom class, into its XML representation, and back again. Every time a message is passed to or from a Web service, XML serialization transpires. (December 17th, 2003)
  • Part 6 - Looks at sending metadata to a Web method through the use of SOAP headers. Examines defining and accepting a SOAP header on the Web service end, and looks at sending a populated SOAP header from the client. (December 31st, 2003)
  • Part 7 - Examines how the incoming and outgoing messages to a Web service can be programmatically modified via SOAP Extensions. (January 21st, 2004)
  • Part 8 - Learn about the Web Service Enhancements (WSE) and Microsoft's free class library for implementing the WSE standards. (June 30th, 2004)
  • Part 9 - See how to implement UsernameToken authentication using the WSE 2.0 Toolkit. (July 14, 2004)
  • Part 10 - Learn how to send large amounts of data as attachments using DIME and WS-Attachments. (September 8th, 2004)
  • Part 11 - Create (and consume) client-side script-accessible Web Services using Microsoft's ASP.NET AJAX framework. (September 26th, 2007)

Introduction


The SOAP structure... In Part 1 of this article series we looked at the pieces involved in using Web services, including SOAP, which is the standard by which the messages passed to and from a Web service are encoded by. As we discussed in Part 1, SOAP messages are comprised of the following parts:

- continued -

  • 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.

<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>
    <Add xmlns="Web Service Namespace">
      <a>5</a>
      <b>8</b>
    </Add>
  </soap:Body>
</soap:Envelope>

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:

  1. Define a SOAP header class in the Web service project
  2. Add a public member variable of the SOAP header class created in step (1) to the Web service class
  3. 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.

public class AuthenticationHeader : SoapHeader
{
  public string Username;
  public string 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:

[WebService(Namespace="http://www.4guys.com/blahblahblah")]
public class MyWebService : System.Web.Services.WebService
{
  public AuthenticationHeader AuthHeader;

  ... The Web service's methods would be defined down here ...
}

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:

[WebMethod()]
public string GetMessage()
{
  if (user is authorized)
    return "This is the secret message!!!";
  else
    return "YOU ARE NOT AUTHORIZED TO SEE THIS MESSAGE!";
}

To allow this method to accept a SOAP header we need to add the SoapHeader attribute like so:

[WebMethod(), SoapHeader("AuthHeader")]
public string GetMessage()
{
  if (user is authorized)
    return "This is the secret message!!!";
  else
    return "YOU ARE NOT AUTHORIZED TO SEE THIS MESSAGE!";
}

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:

[WebMethod(), SoapHeader("AuthHeader")]
public string GetMessage()
{
  // Only allow scott/password to access this secret message...
  if (AuthHeader.Username == "scott" && AuthHeader.Password == "password")
    return "This is the secret message!!!";
  else
    return "YOU ARE NOT AUTHORIZED TO SEE THIS MESSAGE!";
}

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:

  1. Create an instance of the proxy class,
  2. Create an instance of the SOAP header class and populate its values,
  3. 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
  4. 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.

// step 1, create the proxy class
localhost.MyWebService proxy = new localhost.MyWebService();

// step 2, create and populate the header class
localhost.AuthenticationHeader authInfo = new localhost.AuthenticationHeader();
authInfo.Username = "scott";
authInfo.Password = "password";

// step 3, affix the SOAP header to the proxy
proxy.AuthHeaderValue = authInfo;

// step 4, call the method
string result = proxy.GetMessage();

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.

<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>
    <AuthHeader>
      <Username>scott</Username>
      <Password>password</Password>
    </AuthHeader>
  </soap:Header>
  <soap:Body>
    <GetMessage xmlns="Web Service Namespace" />
  </soap:Body>
</soap:Envelope>

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!

  • By Scott Mitchell


    Beginner's .NET XML Web Services

    Beginner's .NET XML Web Services DVD

    Beginner's .NET XML Web Services offers nearly eight hours of training on .NET XML Web services in a video format. This two-disc DVD set, presented by author Scott Mitchell, offers a unique opportunity for learning about the fundamentals of Web services. The 14 lessons begin with an examination of the core Web service standards, and then quickly move into showing you how to create and consume Web services in Microsoft's .NET Framework. There are in-depth lessons for each of the core Web service standards - XML, SOAP, and WSDL - along with examples of the Web Service Enhancements (WSE). Scattered throughout each of these chapters are extensive demos, depicting how to build, deploy, and access Web services using Microsoft's Visual Studio .NET. The DVD also contains a thorough examination of a real-world, end-to-end Web service application.

    Scott Mitchell is the editor and founder of 4GuysFromRolla.com, author of the An Extensive Examination of the Web Services article series, and author of numerous ASP and ASP.NET books.

    [Buy this DVD]

    Why get stuck with a 600-page paperweight when you can learn about .NET Web Services through an interesting and interactive video presentation?



  • ASP.NET [1.x] [2.0] | ASPMessageboard.com | ASPFAQs.com | Advertise | Feedback | Author an Article