Many a time, you may need to persist the value of an object to secondary storage. For example, you may wish to save the values of a couple of
Point objects representing the positioning of an item on screen to secondary storage. The act of "flattening" an object into a serial form is known as serialization. In this article, I will discuss serialization as supported in the .NET framework -- Binary and SOAP serialization. In the next article, I will discuss how to serialize an object into an XML document.
Consider the following class,
BookMark, which is used to stored information about web addresses and their descriptions.
Public Class BookMark Private pURL As String Private pDescription As String Private pNextURL As BookMark Private dateCreated As Date Sub New() dateCreated = Now End Sub Public Sub printIndex() Console.WriteLine(dateCreated) End Sub Property URL() Get Return pURL End Get Set(ByVal Value) pURL = Value End Set End Property Property Description() Get Return pDescription End Get Set(ByVal Value) pDescription = Value End Set End Property Property NextURL() Get Return pNextURL End Get Set(ByVal Value) pNextURL = Value End Set End Property End Class
BookMark class contains properties as well as private variables. The
NextURL property is used to link up multiple
BookMark objects, much like a linked list.
Let's create two
BookMark objects and link them up:
Dim BM1 As New BookMark Dim BM2 As New BookMark BM1.URL = "http://www.amazon.com" BM1.Description = "Amazon.com Web site" BM1.NextURL = BM2 BM2.URL = "http://www.oreilly.com" BM2.Description = "O'Reilly Web Site" BM2.NextURL = Nothing
I will serialize the objects into a binary stream by writing the
Imports System.IO Imports System.Runtime.Serialization.Formatters.Binary '========Binary Serialization========= Function Serialize(ByVal BkMk As BookMark) _ As MemoryStream Dim ms As New MemoryStream Dim fs As New FileStream("c:\BookMarks.dat", _ FileMode.Create, _ FileAccess.Write) Dim formatter As New BinaryFormatter ' serialize to memory stream formatter.Serialize(ms, BkMk) ' serialize to file stream formatter.Serialize(fs, BkMk) ms.Position = 0 Return ms End Function
Before you serialize an object, you need to prefix the class name with the
<Serializable()> Public Class BookMark
I used the
BinaryFormatter class from the
System.Runtime.Serialization.Formatters.Binary namespace to serialize the
BookMark object into a memory stream, as well as into a file stream. The function then returns a memory stream object representing the serialized
'========Binary Serialization========= '---serializing an object graph into a memory stream Dim ms As MemoryStream = Serialize(BM1)
To prove that the object is serialized correctly, I will de-serialize the memory stream and assign it back to a
'---deserializing a memory stream into an object graph Dim newBM As BookMark newBM = Deserialize(ms)
Here is the
Function Deserialize(ByVal ms As MemoryStream) _ As BookMark Dim formatter As New BinaryFormatter Return formatter.Deserialize(ms) End Function
To display the values of the de-serialized
BookMark object, I use the
Sub Print(ByVal BM As BookMark) Do BM.printIndex() Console.WriteLine(BM.URL.ToString & " - " & BM.Description) BM = BM.NextURL Loop Until BM Is Nothing End Sub
You should see the following in the output window:
9/29/2003 1:11:47 AM http://www.amazon.com - Amazon.com Web site 9/29/2003 1:12:06 AM http://www.oreilly.com - O'Reilly Web Site
But how does the binary stream look like? To answer this question, let's take a look at the c:\BookMarks.dat file that we have created in the process.
To view the binary file, simply drag-and-drop it onto Visual Studio .NET. You should see something similar to what is shown in Figure 1:
|Figure 1. Examining the serialized binary file|
A few observations are worth noting at this point:
BookMarkobjects are linked, and the serialization process takes care of the relationships between the two objects.
There are times that you do not want to serialize all of the data in your object. For example, if you do not wish to persist the date and time that the
BookMark objects have been created, you can prefix the variable name (that you do not wish to serialize) with the
<NonSerialized()> Private dateCreated As Date
dateCreated variable will not be serialized.
Besides binary serialization, you can also serialize objects into a platform-agnostic format: you can serialize it into a SOAP message.
SOAPSerialize() subroutine serializes a
BookMark object into an XML document (when building this code, you need a reference to the
Imports System.Runtime.Serialization.Formatters.Soap '========SOAP Serialization========= Sub SOAPSerialize(ByVal BkMk As BookMark) Dim fs As New FileStream("c:\BookMarks.xml", _ FileMode.Create, FileAccess.Write) Dim formatter As New SoapFormatter formatter.Serialize(fs, BkMk) ' serialize to file stream fs.Close() End Sub
So, instead of using the
BinaryFormatter class, I have replaced it with the
SOAPDeserialize() function reads the XML document (containing the SOAP message), de-serializes it, and returns a
Function SOAPDeserialize(ByVal filename As String) As BookMark Dim fs As New FileStream(filename, FileMode.Open, _ FileAccess.Read) Dim formatter As New SoapFormatter Return formatter.Deserialize(fs) ' serialize to file stream End Function
Here is how you can call the previous two methods:
'========SOAP Serialization========= SOAPSerialize(BM1) newBM = SOAPDeserialize("c:\ BookMarks.xml") '---printing the object graph Print(newBM)
And the SOAP message generated would look something like this:
<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:clr="http://schemas.microsoft.com/soap/encoding/clr/1.0" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <SOAP-ENV:Body> <a1:BookMark id="ref-1" xmlns:a1="http://schemas.microsoft.com/clr/nsassem/WindowsApplication1 /WindowsApplication1%2C%20Version%3D1.0.1125.1874%2C%20Culture%3Dneutral %2C%20PublicKeyToken%3Dnull"> <pURL id="ref-3">http://www.amazon.com</pURL> <pDescription id="ref-4">Amazon.com Web site</pDescription> <pNextURL href="#ref-5"/> </a1:BookMark> <a1:BookMark id="ref-5" xmlns:a1="http://schemas.microsoft.com/clr/nsassem/WindowsApplication1 /WindowsApplication1%2C%20Version%3D1.0.1125.1874%2C%20Culture%3Dneutral%2C %20PublicKeyToken%3Dnull"> <pURL id="ref-6">http://www.oreilly.com</pURL> <pDescription id="ref-7">O'Reilly Web Site</pDescription> <pNextURL xsi:null="1"/> </a1:BookMark> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
Serialization is one good way to preserve the state of an object. It is commonly used for network communications, where you need to pass an object from one machine to another. Another good use of serialization is to use it to clone an object -- serialize an object, de-serialize it, and assign to another object. Voilà! You have an identical copy of the object.
In the next article, I will show you how to serialize an object into an XML document.
Wei-Meng Lee (Microsoft MVP) http://weimenglee.blogspot.com is a technologist and founder of Developer Learning Solutions http://www.developerlearningsolutions.com, a technology company specializing in hands-on training on the latest Microsoft technologies.
Return to ONDotnet.com
Copyright © 2009 O'Reilly Media, Inc.