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 17, 2003

An Extensive Examination of Web Services: Part 5

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


Welcome to the 5th installment of an Extensive Examination of Web Services. In Part 1 we examined the basics of Web services, looking at what, precisely, standards made up Web services. In this first article we discussed SOAP, which stands for Simple Object Access Protocol, and is the standard used for formatting the messages passed between the client consuming the Web service, and the Web service itself. Recall that invoking a Web service involves two messages:

- continued -

  1. A request message, in which a client invokes a particular method of the Web service, passing in input parameters, if applicable, and
  2. A response message, in which the Web service indicates that the method has been called, and returns the method's return value, if applicable.

As we looked at in Part 1, a SOAP-formatted request message has the following form:

<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>
    <WebServiceName xmlns="Web Service Namespace">
      <inputParameter1>input parameter value</inputParameter1>
      <inputParameter2>input parameter value</inputParameter2>
      ...
      <inputParameterN>input parameter value</inputParameterN>
    </WebServiceName>
  </soap:Body>
</soap:Envelope>

While the SOAP-formatted response message has the following form:

<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>
    <WebServiceNameResponse xmlns="Web Service Namespace">
      <WebServiceNameResult>result value</WebServiceNameResult>
    </WebServiceNameResponse>
  </soap:Body>
</soap:Envelope>

Notice that the request message can have a variable number of input parameters, and the response can have an optional result value (the method's return value). Both the input and output parameter values are formatted as XML. For example, a Web service method called Add that took in as input two integers inputs - x and y - and returned the sum as an integer, would have the following request and response messages if the client wished to determine the sum of 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">
      <x>5</x>
      <y>8</y>
    </Add>
  </soap:Body>
</soap: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>
    <AddResponse xmlns="Web Service Namespace">
      <AddResult>13</AddResult>
    </AddResponse>
  </soap:Body>
</soap:Envelope>

Notice that the client and the server are sending and receiving the input and output parameter values as XML. However, .NET does not store an integer in memory as XML markup; rather, it stores as integer as an Int32 structure. This implies that at some point the client, when calling the Add() method, must convert the integers 5 and 8 into an XML representation. Similarly, when the Web service receives the XML representation of 5 and 8 it must convert this XML representation back into Int32 structures.

This process is known as message serialization and message deserialization, respectively, and is the focus of this fifth part of the article series. In this article we'll look at the serialization and deserialization process, and see how even complex types - such as custom classes and arrays - can be effortlessly serialized and deserialized.

An Overview of XML Serialization


When working with data in a computer program, typically the data is located in the memory (RAM) of the computer on which the program is running. For example, when you are creating a letter in Microsoft Word, the contents of your letter, the formatting, and much other miscellaneous information is stored in the computer's memory. Now, imagine that you wanted to save the Word document to a file. How is this accomplished?

Clearly there needs to be some way for the data to be persisted. But the format of the data in the computer's memory may not be the ideal format to have it stored on the hard drive. Therefore there needs to be some conversion from the data's representation in memory to a representation suitable for storing it on disk. The process of converting data from one format to another is known as serialization. Once data has been serialized from one format to another, we typically will want to, at some later point in time, convert it back to the original format. This inverse operation is referred to as deserialization.

The .NET Framework provides a number of serialization options. The one that is pertinent to Web services is XML serialization, which involves serializing in-memory data to an XML format. With Web services this XML-formatted version of the data is sent from the client consuming the Web service, to the Web service, or vice-a-versa. The nice thing about the .NET Framework's XML serialization capabilities is that we, the developer, have to do very little, if anything, to benefit from it.

Persisting Data to Disk with XML Serialization
XML serialization is not limited in use to just Web services. For example, you can persist an object to disk using XML serialization. This could be used in a WinForms application to save data to the hard drive in a format that's easily viewable and modifiable by power users. For more information on XML serialization and some code samples of explicitly using the XmlSerializer class, be sure to read Anthony Hart's article XML Serialization in ASP.NET.

XML serialization is preformed by the XmlSerializer class. This class has two important methods: Serialize(stream, object) and Deserialize(stream). The Serialize() method takes in a stream and an object instance; it converts the object into its XML representation and squirts it out to the passed-in stream. Conversely, the Deserialize() method takes in a stream instance with the XML-formatted data, and deserializes it, returning an object instance.

When calling a Web service through the auto-generated proxy class, the data types being passed to the Web service are automatically serialized via XmlSerializer. Similarly, when the serialized data reaches the Web service it is automatically deserialized before being handed off to the called Web method. Inversely, when the Web methods sends its return value, that value is automatically serialized into XML, sent back to the client, and is then deserialized automatically. The figure below illustrates this concept:

A graphical representation depicting XML serialization in a Web service invocation.

Serializing Complex Data Types


As we've seen with some of the simple Web service examples we've examined throughout this article series thus far, it is apparent that the .NET Framework's XML serialization can serialize simple data types, like strings, integers, floats, date/times, and so forth. The XmlSerializer class can, additionally, serialize complex data types, such as collections and custom classes. Since Web services use XmlSerializer this means we can pass complex data types effortlessly to and from Web services!

For example, imagine that we wanted to create a Web service method that accepted an input parameter of type CreditCardInfo, which was a class defined with public properties like CardNumber, ExpirationMonth, and ExpirationYear. The following code shows the Web service class, with its method MakeDebit() method that takes in two parameters: a CreditCardInfo instance and an amount.

public class MyWebService : System.Web.Services.WebService
{
  [WebMethod()]
  public void MakeDebit(CreditCardInfo ccInfo, float amount)
  {
    // ... process the credit card ...
  }
}

public class CreditCardInfo
{
  private string _number;
  private int _expMonth, _expYear;

  public string CardNumber
  {
    get { return _number; }
    set  { _number = value;}
  }

  public int ExpirationMonth
  {
    get  { return _expMonth;  }
    set  { _expMonth = value;}
  }

  public int ExpirationYear
  {
    get { return _expYear; }
    set  { _expYear = value;}
  }
}

Notice that after the Web service class we provide our definition of the CreditCardInfo class. This class is relatively straightforward - it has three public properties as discussed earlier. When creating a client to consume this Web service, you would create the proxy class through Visual Studio .NET or using wsdl.exe as discussed in Part 3 of this article series.

The proxy class created on the client would contain a method called MakeDebit() that took in an object of type CreditCardInfo. Also created on the client would be a class named CreditCardInfo. The client could call MakeDebit() with the following few lines of code:

// create an instance of the proxy class
MyWebService proxy = new MyWebService();

// create an instance of the CreditCardInfo object
CreditCardInfo cc = new CreditCardInfo();
cc.CardNumber = "1111222233334444";
cc.ExpirationMonth = 2;
cc.ExpirationYear = 2005;

// call MakeDebit()
proxy.MakeDebit(cc, 4.95F);

The XML serialization process would serialize the CreditCardInfo class instance in this example to the following XML:

<CreditCardInfo>
  <CardNumber>1111222233334444</CardNumber>
  <ExpirationMonth>2</ExpirationMonth>
  <ExpirationYear>2005</ExpirationYear>
</CreditCardInfo>

This information, along with the second input parameter (amount), would be packaged into a SOAP-formatted message and sent to the Web service via an HTTP request. The Web service, upon receiving this request, would deserialize the input parameters, converting the CreditCardInfo XML content back into an in-memory instance of type CreditCardInfo.

Some Closing Notes on XML Serialization


There are a few subtle details with XML serialization that are important to know about when working with Web services that accept complex data types. Realize that XML serialization:

  • XML serialization can only be applied to classes that contain a public default (parameterless) constructor. If you create a class in the Web service that does not have a public default constructor, the Web service will still compile, but when attempting to generate the proxy class on the client's end you'll receive an error message.
  • Read-only class properties are not serialized. That is, if a property in the class has only a get accessor, and not a set accessor as well, the property will not be serialized.
  • Only public properties and fields are serialized. Private properties are not serialized.
  • To serialize a strongly-typed collection of objects, have the class derived from System.Collections.CollectionBase adding an Add() method and an indexer. (See this article for more information.) Alternatively you can send an array of the specified type.

On the last point, consider the case where you want a Web service method to accept a set of custom class instances. For example, we looked at a custom CreditCardInfo class - imagine you wanted to build a Web method that accepted a number of instances of type CreditCardInfo. One option is to have the method accept an array of type CreditCardInfo, like so:

[WebMethod()]
public void FooBar(CreditCardInfo [] collectionOfCCInfos)
{
   ...
}

Another option is to create a strongly-typed collection class derived from System.Collections.CollectionBase. You'd then pass in an instance of this strongly-typed collection class. For example, you'd first create the class:

public class CreditCardInfoCollection : System.Collections.CollectionBase
{
  public void Add(CreditCardInfo cc)
  {
    this.InnerList.Add(cc);
  }
  
  public CreditCardInfo this[int index]
  {
    get { return (CreditCardInfo) this.InnerList[index]; }
    set { this.InnerList[index] = value; }
  }
}

And then you'd have the Web service method accept an input of this strongly-typed collection class:

[WebMethod()]
public void FooBar(CreditCardInfoCollection collectionOfCCInfos)
{
   ...
}

Conclusion


In this article we examined the process by which input and output parameter values to a Web service method are converted to and from an XML format. This process is known as XML serialization and deserialization, and (with Web services) is handled for us behind the scene with the XmlSerializer class. Along with simple, scalar data types, the XmlSerializer class can also serialize and deserialize complex data types, such as arrays and custom classes. Thanks to this power, we can effortlessly create Web services that accept non-trivial data types.

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