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.
|
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:
- A request message, in which a client invokes a particular method of the Web service, passing in input parameters, if applicable, and
- 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:
|
While the SOAP-formatted response message has the following form:
|
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:
|
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:

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
.
|
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:
|
The XML serialization process would serialize the CreditCardInfo
class instance in this example to the
following XML:
|
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 aset
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 anAdd()
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:
|
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:
|
And then you'd have the Web service method accept an input of this strongly-typed collection class:
|
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!
|