.NET Framework Runtime Serialization

Introduction

Anyone who has ever worked with document parts know that the different regions of the document - areas that hold images and logos, text fields, and controls - are stored differently in memory. In fact, when we develop a .NET application, we probably do not think about how the data is stored in memory. The Framework handles that for you. However, if you want to store the contents of an object to a file, send an object to another process, or transmit it across the network, you do have to think about how the object is represented because you will need to convert it to a different format. This conversion is called serialization. More to the point, since the CLR uses automatic memory management to track an object's life cycle by keeping a graph of the objects that are reachable and therefore still usable, serialization is the process of converting an object or a connected graph of objects into a contiguous stream of bytes. Deserialization is the process of converting a contiguous stream of bytes back into its graph of connected objects. The ability to convert objects to and from a byte stream provides many useful and practical mechanisms:

An application's state (object graph) can easily be saved in a disk file or database and then restored the next time the application is run. ASP.NET saves and restores session state by way of serialization and deserialization.

A set of objects can easily be copied to the system's clipboard and then pasted into the same or another application. In fact, Windows® Forms uses this procedure.

A set of objects can be cloned and set aside as a backup while a user manipulates the main set of objects.

A set of objects can easily be sent over the network to a process running on another machine. The .NET Framework remoting architecture serializes and deserializes objects that are marshaled by value.

This article will focus on serialization, as implemented in the System.Runtime.Serialization namespace. Serializing and deserializing objects allow them to be stored or transferred and then later recreated. Serializing an object converts an object into a linear sequence of bytes that can be stored or transferred. Deserializing an object converts a previously serialized sequence of bytes into an object.

How to Serialize an Object

At a high level, the steps for serializing an object are as follows:

Create a stream object to hold the serialized output.

Create a BinaryFormatter object.

Call the BinaryFormatter.Serialize method to serialize the object, and output the result to stream.

Consider this basic code that serializes a string of data:

using System;
using System.Runtime.Serialization;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
publicsealedclass Program {
publicstaticvoid Main() {
string data = "this must be stored in a file";
// create the file to store the data to
FileStream fs = new FileStream("SerializedString.Data",
FileMode.Create);
// create binary formatter object to perform serialization
BinaryFormatter bf = new BinaryFormatter();
// use the BinaryFormatter object to serialize the data to the file
bf.Serialize(fs, data);
fs.Close();
}
}

After compiling this code, we use the command 'notepad SerializedString.Data':

Serialized objects can be stored as files, but are not text files.

Now, consider this code that deserializes the object stored in the file:

using System;
using System.Runtime.Serialization;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
publicsealedclass Program {
publicstaticvoid Main() {
//notice that the FileMode is now Open and not Create
FileStream fs = new FileStream("SerializedString.Data",
FileMode.Open);
BinaryFormatter bf = new BinaryFormatter();
string data = "this must be stored in a file";
data = (string) bf.Deserialize(fs);
fs.Close();
Console.WriteLine(data);
}
}

Here is the output, or the reverse of the initial process used to convert the object into a continuous stream of bytes:

It is not likely at all that one string of data needs to be converted into an object and then serialized and stored in a text file, but the example is meant to illustrate the underlying principle behind the topic of the article. For that purpose, consider another example:

The reader should note that the inner workings of deserialization within the runtime can be a complex process. The CLR proceeds through the deserialization process sequentially, starting at the beginning and working its way through to the end. Recall that serialization is the process of converting an object into a continuous stream of bytes. The process gets complicated if an object in the serialized stream refers to another object. If an object refers to another object, the Formatter (which will be discussed later) queries the Object Manager to determine whether the referenced object has already been deserialized (a backward reference in the contiguous stream), or whether it has not been referenced (a forward reference).

XML Serialization

XML is a standardized, text-based document format for storing application-readable information. Just as HTML provides a text-based standard for formatting human-readable documents, XML provides a standard that can easily be processed by a computer or any networked machine. The steps to use XML to serialize an object are:

Create a stream, TextWriter, or XmlWriter object to hold the serialized output.

Create an XMLSerializer object (in the System.Xml.Serialization namespace) by passing it the type of object you plan to serialize.

Call the XmlSerializer.Serialize method to serialize the object and output the results to the previously created stream (in step 1).

<?xmlversion="1.0"?><dateTime>2009-05-23T17:07:45.8726619-04:00>

To deserialize the object using XML, you should follow these steps:

Create a stream, TextReader, or XmlReader object to hold the serialized output.

Create an XMLSerializer object (in the System.Xml.Serialization namespace) by passing it the type of object you plan to deserialize.

Call the XmlSerializer.Deserialize method to serialize the object, and cast it to the correct type.

Here is the sample code used to deserialize the object:

using System;
using System.Runtime.Serialization;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Xml.Serialization;
publicsealedclass Program {
publicstaticvoid Main() {
// create a file to save the data to
FileStream fs = new FileStream("SerializedString.Date", FileMode.Open);
// create an XmlSerializer object to perform the serialization
XmlSerializer xs = new XmlSerializer(typeof(DateTime));
// use the XmlSerializer object to serialize the data to a file
DateTime previousTime = (DateTime)xs.Deserialize(fs);
// close the file
fs.Close();
// display the deserialized time
Console.WriteLine("Day: " + previousTime.DayOfWeek +
" ,Time: " + previousTime.TimeOfDay.ToString());
}
}

The output:

Choosing a Serialization Format

Up until this point, we have used the BinaryFormatter from the System.Runtime.Serialization.Formatters.Binary namespace. This formatter is the most efficient way to serialize objects that will be read by only .NET Framework-based applications. The SoapFormatter, located in the System.Runtime.Serialization.Formatters.Soap namespace, is XML-based, and is primarily meant to be used by SOAP Web Services. To use the SoapFormatter, substitute the SoapFormatter class for the BinaryFormatters class. Here is an example. To use these examples, by the way, just type type con > NameOfFile.cs at the framework command prompt, copy the code and paste it onto the console, press Ctrl-Z, and then compile the code:

Putting it All Together

We now know that serialization is the runtime process that converts an object, or a graph of objects, to a linear sequence of bytes. You can then use the resultant block of memory either for storage or transmission over the network on top of a particular protocol. In .NET object serialization, we can have three output forms: binary, SOAP, and XML. Runtime object serialization (for example, binary and SOAP) and XML serialization are different technologies with different implementations and goals. To use the SoapFormatter, you must reference a distinct assembly: System.System.Runtime.Serialization.Formatters.Soap.dll, by importing that namespace:

using System.Runtime.Serialization.Formatters.Soap;

XML serialization is handled by the XmlSerializer class. It is similar to binary and SOAP formatters because it also persists and restores the object's state. Unzip the downloadable files into a newly made folder in your Visual Studio 2005(8) projects folder, and double-click the solution file. This Windows Forms application will enable you to gain a sharper focus on these serialization technologies.