Improve Your Technology

Just another blog for techology

Binary Serialization

Binary Serialization

 

Serialization can be defined as the process of storing the state of an object to a storage medium. During this process, the public and private fields of the object and the name of the class, including the assembly containing the class, are converted to a stream of bytes, which is then written to a data stream. When the object is subsequently deserialized, an exact clone of the original object is created.

When implementing a serialization mechanism in an object-oriented environment, you have to make a number of tradeoffs between ease of use and flexibility. The process can be automated to a large extent, provided you are given sufficient control over the process. For example, situations may arise where simple binary serialization is not sufficient, or there might be a specific reason to decide which fields in a class need to be serialized. The following sections examine the robust serialization mechanism provided with the .NET Framework and highlight a number of important features that allow you to customize the process to meet your needs.

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

The 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 Serialize() function:

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()> attribute:

<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 BookMark object.

‘========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 BookMark object:

‘—deserializing a memory stream into an object graph

Dim newBM As BookMark

newBM = Deserialize(ms)

Here is the DeSerialize() function:

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 Print() subroutine:

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

Some Observations

A few observations are worth noting at this point:

  • Private variables and properties are all serialized. In binary serialization, both the private variables and properties are serialized. This is known as deep serialization, as opposed to shallow serialization in XML serialization (which only serializes the public variables and properties). I will discuss XML serialization in the next article.
  • Object graphs are serialized. In our example, two BookMark objects 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()> attribute:

<NonSerialized()> Private dateCreated As Date

The dateCreated variable will not be serialized.

Advertisements

September 18, 2008 Posted by | Binary Serialization, Serialization, Technology | , | Leave a comment

XML Serialization in the .NET Framework

XML Serialization in the .NET Framework 

Dare Obasanjo
Microsoft Corporation

January 23, 2003

Overview of XML Serialization in the .NET Framework

The primary purpose of XML serialization in the .NET Framework is to enable the conversion of XML documents and streams to common language runtime objects and vice versa. Serialization of XML to common language runtime objects enables one to convert XML documents into a form where they are easier to process using conventional programming languages. On the other hand, serialization of objects to XML facilitates persisting or transporting the state of such objects in an open, standards compliant and platform agnostic manner.

XML serialization in the .NET Framework supports serializing objects as either XML that conforms to a specified W3C XML Schema Definition (XSD) schema or that is conformant to the serialization format defined in section five of the SOAP specification. During XML serialization, only the public properties and fields of an object are serialized. Also, type fidelity is not always preserved during XML serialization. This means that if, for instance, you have a Book object that exists in the Library namespace, there is no guarantee that it will be deserialized into an object of the same type. However, this means that objects serialized using the XML serialization in the .NET Framework can be shipped from one machine to the other without requiring that the original type be present on the target machine or that the XML is even processed using the .NET Framework. XML serialization of objects is a useful mechanism for those who want to provide or consume data using platform agnostic technologies such as XML and SOAP.

XML documents converted to objects by the XML serialization process are strongly typed. Data type information is associated with the elements and attributes in an XML document through a schema written in the W3C XML Schema Definition (XSD) Language. The data type information in the schema allows the XmlSerializer to convert XML documents to strongly typed classes.

For more information about XML serialization in the .NET Framework, read the SDK documentation topic entitled XML and SOAP Serialization.

The Book Inventory Application

In my previous articles, I created an XML document that listed all my books and described their availability in my personal library. Upon reflection, I decided that I’d prefer a GUI interface for viewing and manipulating the document instead of editing the raw XML file in a text editor. The first step I took in creating this application was to look at the classes in the System.Windows.Forms namespace to see if any could satisfy my needs out of the box. The DataGrid class looked promising.

The description of potential data sources for the DataGrid class included single dimensional arrays, which struck a chord because I imagined that a sequential listing of books is something that could be mapped to an array by XML serialization. I decided to give this a try by converting the schema shown below to a C# class.

<?xml version="1.0" encoding="UTF-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" 
targetNamespace="urn:xmlns:25hoursaday-com:my-bookshelf" 
xmlns:bk="urn:xmlns:25hoursaday-com:my-bookshelf" 
elementFormDefault="qualified">
   <xs:element name="books">
      <xs:complexType>
         <xs:sequence>
            <xs:element name="book" type="bk:bookType" 
maxOccurs="unbounded" />
         </xs:sequence>
      </xs:complexType>
   </xs:element>
   <xs:complexType name="bookType">
      <xs:sequence>
         <xs:element name="title" type="xs:string" />
         <xs:element name="author" type="xs:string" />
         <xs:element name="publication-date" type="xs:date" />
      </xs:sequence>
      <xs:attribute name="publisher" type="xs:string" />
      <xs:attribute name="on-loan" type="xs:string" />
   </xs:complexType>

</xs:schema>

The .NET Framework SDK provides the XML Schema Definition Tool xsd.exe that can be used to convert XSD schemas to C# classes. I converted my schema file to C# source file issuing the following commands on the command line:

                xsd.exe  /c books.xsd

The generated C# class is decorated with attributes that provide information on how the XmlSerializer converts the class to XML. The XmlRootAttribute, XmlElementAttribute, and XmlAttributeAttribute attributes are used to specify which classes, fields, or properties become the root, element, and attribute nodes in the generated XML. The class generated from the schema is shown below.

using System.Xml.Serialization;
 /// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(Namespace=
"urn:xmlns:25hoursaday-com:my-bookshelf")]
[System.Xml.Serialization.XmlRootAttribute("books", 
Namespace="urn:xmlns:25hoursaday-com:my-bookshelf", IsNullable=false)]
public class books {
      /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute("book")]
    public bookType[] book;
}
 /// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(Namespace=
"urn:xmlns:25hoursaday-com:my-bookshelf")]
public class bookType {
     /// <remarks/>
    public string title;
      /// <remarks/>
    public string author;
     /// <remarks/>
   [System.Xml.Serialization.XmlElementAttribute("publication-date", 
DataType="date")]      
    public System.DateTime publicationdate;
     /// <remarks/>
    [System.Xml.Serialization.XmlAttributeAttribute()]
    public string publisher;
      /// <remarks/>
    [System.Xml.Serialization.XmlAttributeAttribute("on-loan")]
    public string onloan;

}

Note   The attribute that annotates the publicationdate field has a DataType property. There is no type in the .NET Framework that matches the type xs:date completely. The closest match is System.DateTime, which stores date and time data. Specifying the DataType property as a “date” ensures that the XmlSerializer will only serialize the date part of the DateTime object.

The XmlSerializer mapped the multiple book elements of type bookType in my schema to an array of bookType objects named book. I thought I was ready to bind my classes to the DataGrid until I noticed a section of the documentation on Data Sources for the DataGrid Control which pointed out that the objects in an array must have public properties if they are to be bound to a DataGrid. Since the XSD tool created public fields, I had to fix my classes by making the fields private and exposing them through properties instead. Then, I also had to move the XML serialization specific attributes from the fields to the properties because the XmlSerializer only checks for attributes on public fields and properties. Below is the altered bookType class.

/// <remarks/>
   [System.Xml.Serialization.XmlTypeAttribute(Namespace=
"urn:xmlns:25hoursaday-com:my-bookshelf")]
   public class bookType 
   {
      /// <remarks/>
      private string _title;
      public string title{
         get{ return _title; }
         set { _title = value; }
      }
         /// <remarks/>
      private string _author;
      public string author
      {
         get{ return _author; }
         set { _author = value; }
      }
     /// <remarks/>
      private  System.DateTime _publicationdate;
      [System.Xml.Serialization.XmlElementAttribute("publication-date",
 DataType="date")]      
      public System.DateTime publicationdate
      {
         get{ return _publicationdate; }
         set { _publicationdate = value; }
      }
     private string _publisher;
      /// <remarks/>
      [System.Xml.Serialization.XmlAttributeAttribute()]
      public string publisher
      {
        get{ return _publisher; }
         set { _publisher = value; }
      }
       private  string _onloan;
      [System.Xml.Serialization.XmlAttributeAttribute("on-loan")]      
      public string onloan
      {
         get{ return _onloan; }
         set { _onloan = value; }
      }

   }

With the aforementioned changes, it is now possible to bind my list of books as XML to a DataGrid. Firing up the Visual Studio® .NET forms designer, I quickly dragged and dropped a DataGrid onto a form, along with a couple of buttons for navigation purposes. The final step was to add some code to ensure that the DataGrid was bound to my XML once the form was loaded. The Form_Load method in my class is shown below.

private void Form1_Load(object sender, System.EventArgs e)
     {
       try{
         TextReader reader = new StreamReader("books.xml");
         XmlSerializer serializer = new XmlSerializer(typeof(books));
         myBooks = (books)serializer.Deserialize(reader);
         reader.Close();
          //currency manager used for cursoring through book array in UI
         currencyManager = 
(CurrencyManager)dataGrid1.BindingContext[myBooks.book];
          dataGrid1.DataSource= myBooks.book;
        }catch(XmlException xe){
         MessageBox.Show (xe.Message, "XML Parse Error", 
                MessageBoxButtons.OK, MessageBoxIcon.Error);
        }catch(InvalidOperationException ioe){
         MessageBox.Show (ioe.InnerException.Message, "XML 
Serialization Error", 
                MessageBoxButtons.OK, MessageBoxIcon.Error);
  }

}

And that’s all it takes. Shown below is the XML document I plan to edit with my application.

<books xmlns="urn:xmlns:25hoursaday-com:my-bookshelf" >
  <book publisher="QUE">
    <title>XML By Example</title>
    <author>Benoit Marchal</author>
    <publication-date>1999-12-31</publication-date>
  </book>
  <book publisher="Addison Wesley" on-loan="Dmitri">
    <title>Essential C++</title>
    <author>Stanley Lippman</author>
    <publication-date>2000-10-31</publication-date>
  </book>
  <book publisher="WROX">
    <title>XSLT Programmer's Reference</title>
    <author>Michael Kay</author>
    <publication-date>2001-04-30</publication-date>
  </book>
  <book publisher="Addison Wesley" on-loan="Sanjay">
    <title>Mythical Man Month</title>
    <author>Frederick Brooks</author>
    <publication-date>1995-06-30</publication-date>
  </book>
  <book publisher="Apress">
    <title>Programmer's Introduction to C#</title>
    <author>Eric Gunnerson</author>
    <publication-date>2001-06-30</publication-date>
  </book>

</books>

Figure 1 below shows a DataGrid bound to the above XML document in my Book Inventory application .

 

Figure 1. The Book Inventory application

It should be noted that although my application allows me to edit the contents of my XML document bound to the DataGrid, I cannot add or delete new books to my inventory file. The inability to add modify the number of books through the DataGrid is a limitation imposed on it when bound to arrays. This issue does not exist when bound to other data sources.

For the purpose of completeness, I should highlight an alternative approach to solving my data binding problem. I could have loaded the XML document and schema into a DataSet using the ReadXml() and ReadXmlSchema() methods respectively, then bound that to the DataGrid. Descriptions of how to use this alternate approach are available in the .NET SDK documentation in the section entitled Generating DataSet Relational Structure from XML Schema (XSD). A code example using the DataSet class instead of XML serialization is also included in the download file for the article.

SOAP Serialization

Besides binary serialization, you can also serialize objects into a platform-agnostic format: you can serialize it into a SOAP message.

The SOAPSerialize() subroutine serializes a BookMark object into an XML document (when building this code, you need a reference to the System.Runtime.Serialization.Formatters.Soap.dll assembly):

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 SoapFormatter class.

The SOAPDeserialize() function reads the XML document (containing the SOAP message), de-serializes it, and returns a BookMark object:

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&#8221;

 xmlns:xsd=”http://www.w3.org/2001/XMLSchema&#8221;

 xmlns:SOAP-ENC=”http://schemas.xmlsoap.org/soap/encoding/&#8221;

 xmlns:SOAP-ENV=”http://schemas.xmlsoap.org/soap/envelope/&#8221;

 xmlns:clr=”http://schemas.microsoft.com/soap/encoding/clr/1.0&#8243;

SOAP-ENV:encodingStyle=”http://schemas.xmlsoap.org/soap/encoding/”&gt;

 

<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&gt;

      <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&gt;

      <pDescription id=”ref-7″>O’Reilly Web Site</pDescription>

      <pNextURL xsi:null=”1″/>

   </a1:BookMark>

</SOAP-ENV:Body>

 

</SOAP-ENV:Envelope>

Uses of Serialization

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.

September 16, 2008 Posted by | Serialization, Technology, XML Serialization | , , | 1 Comment