[
Advertise | Submit Code | About us | Contact us | Link us
]
Go!
Membership Services
Login
Register

Home
C# General

General

C# Language

Design & Architecture

Algorithms

Database

Security

Active Directory

COM Interop

Remoting
C# Windows Forms

General

Combo and List boxes

Miscellaneous Controls

Button Controls

Edit Controls
Cutting Edge

ASP.NET 2.0

Visual Studio 2005

Windows Longhorn

SQL Server 2005
C# Multimedia and GDI+

General

DirectX

GDI+

Audio
Internet & Web

General

Images and multimedia

Database

Utilities

Security

ASP.NET Controls

Design and Architecture

Webservices
.NET

General

Design & Architecture

Algorithms

Database

Security

Active Directory

COM Interop

Remoting

ADO.NET

XML.NET

Tools

Enterprise

IDE
Visual Basic .NET

VB.NET General

VB.NET Controls
General Reading

.NET Books Review

Product Showcase

Book Chapters

Business Design & Strategy
Community

Discuss

Job Board

Discussion

CodeXchange
DeveloperLand

Advertise

Submit Code

About us

Contact us

Link us
Miscellaneous

Favorite Links

Downloads

Programming Sites

Top Stories
Regular Expressions

E-Mail

Date/Time
Home > .NET > General
Real world .NET serialization
Posted by on Friday, October 01, 2004 (EST)

Do you know what Jeff Richter didn't tell you about .NET serialization? Read on and learn what I've learned the hard way applying serialization to a real world .NET project.

This article has been viewed: 2,751 times
Technology: General.

serialization sample.zip (78.72 KB)

Contents

Introduction

This article can be regarded as a "free continuation" of the article "My first .NET project [^]", because the issues explained here are drawn from that same project. For those of you who didn't read the article, I'd recommend to read at least the first few paragraphs in order to get familiar with the project's requirements and architecture...

About the time .NET Framework 1.0 was released I managed to win a project whose large part consisted of parsing and processing large amounts of text. The text was in the form of huge, semi-structured files (representing a kind of legislative documents). The project's job was mainly to:

  • Parse the files and display the parsed tree-like structure to the user.
  • Let the user edit the hierarchical structure and the contents of the individual nodes.
  • Save the (potentially modified) hierarchical structure to an SQL database.
I've designed the application to consist of three major parts:
  • The parsing engine to parse an input file and produce an in-memory tree of Block objects (I've used the System.Text.RegularExpressions classes for this). The Block tree was wrapped in a BlockSet object (more on that later).
  • The user interface controls and windows for display and modification of the Block tree and the individual Block objects.
  • The DB class responsible for saving and restoring BlockSets to / from database.

Top Go to Table of Contents

Now let's go back to the project.

Shortly after I released my first BETA, the customer requested a new feature that would allow the editors to work offline, i.e. disconnected from the central database. Suddenly I had to implement a file-based persistence.

I've researched some of the design options and I've quickly discovered the System.Runtime.Serialization namespace. I've flipped through the documentation and read the Jeff Richter's excellent series of articles about serialization ( #1 [^], #2 [^] and #3 [^])

I was a bit lazy so I took the easier path of "automatic" serialization. I've rushed through the source code adding the Serializable attribute to the Block class, the BlockSet class and some other helper classes found in the hierarchy. After that, I've added a code to actually serialize and deserialize the Block graph, which was rather easy (look at this sample [^] from the official documentation).

I've launched the application, created a simple Block tree and then I've invoked the command to save the tree to disk. Guess what? I've got a SerializationException saying that "Serialization will not deserialize delegates to non-public methods."

Of course, the BlockSet class had several private event handling methods and they were hooked to the underlying Block events. But why they couldn't be deserialized is beyond me. After all, they were already serialized, right?

I can only speculate that this has something to do with security and I'd really appreciate if someone can explain the reasoning behind this "non-public delegates" exception.

I've even searched through the MONO [^] and Rotor [^] project's source code and I've found that the deserialization code just checks if the delegate being deserialized is public and if not, it throws an exception. Without any comments.

(Rotor: See the DelegateSerializationHolder.GetDelegate(DelegateEntry) method in the delegateserializationholder.cs file. MONO: See the DeserializeDelegate(SerializationInfo) method)

At this point I stopped struggling with the "automatic" serialization approach opting to implement ISerializable. (I could just make the Block's private event handlers public, but I didn't want to do it. You know, I'm an OO purist:-). I've implemented the ISerializable.GetObjectData method serializing just the data fields. I've implemented the required deserialization constructor to do the deserialization.

Everything worked great!

The application eventually went to production and the users were happily saving and loading their Block trees to and from disk files. After a few weeks, the customer asked to add an additional Notes property to the Block class.

There you have it -VERSIONING!

Here is how I did it with the Block class.

This code shows the deserialization constructor before the new Notes property was added:

Protected Sub New( _
 ByVal info As SerializationInfo, _
 ByVal context As StreamingContext)
 ...
 _dateFrom = info.GetDateTime("_dateFrom")
 _dateTo = info.GetDateTime("_dateTo")
 _caption = info.GetString("_caption")
 ...
End Sub
This is the new code:
Protected Sub New( _
 ByVal info As SerializationInfo, _
 ByVal context As StreamingContext)
 ...
 _dateFrom = info.GetDateTime("_dateFrom")
 _dateTo = info.GetDateTime("_dateTo")
 _caption = info.GetString("_caption")
 
 Try
  _notes = info.GetString("_notes")
 Catch
  _notes = String.Empty
 End Try
 
 ...
End Sub

Top Go to Table of Contents

Simple, isn't it? Elegant? Far from it, IMHO.

I'd expect the SerializationInfo class to have some kind of "lookup" method to query if a slot with a given name is present in the deserialized data, but there is no such method. One approach would be to call SerializationInfo.GetEnumerator and find out if a slot with a given name exists by "manually" iterating through the returned SerializationInfoEnumerator object. Another approach would be trying to read a named slot and ignoring the exception when no slot with a given name exists. This is what I did in the example above.

(I know that the latter approach violates the rule [^] that one should never use exceptions to handle the "normal" code flow, but I can live with that:-).

To wrap things up, here is the message I'd like you to remember:

Always implement ISerializable and never rely on the "automatic" serialization.

When you start with a simple class it might be tempting to use the "automatic" serialization mechanism just by adding the Serializable attribute to your class. Please, don't do it. (Remember, we've been talking about real applications, not about code samples or quick starts or whatever...) Sooner or later you will have to extend the class (by adding a property, changing a property's type, removing property...) and your code will have to read serialization streams created with the old code.

This kind of versioning simply cannot be reasonably implemented without using ISerializable.

To better illustrate the differences between the "automatic" and ISerializable approaches, I've built two VB projects--AutomaticSerialization.vbproj and ISerializableSerialization.vbproj. They are both contained within the Serialization.sln solution file.

I hope it will be an inspirational reading.

Top Go to Table of Contents

About Palo Mraz

Click here if you want to know more about .

Other articles that may interest you

  • Write a Word Add-In – Part 0
  • Write a Word Add-In – Part I
  • Lengthy Operations on Single Thread in .NET Application
  • Learning Draughts
  • Exceptions and Performance
  • Average Rating :

    Discussion Forums
    Got a programming related question? Hopefully someone has the answer... Want to help out other developers? Visit our discussion forums.

    Sponsored by:

    New Articles

  • Exceptions and Performance
    Almost every time exceptions are mentioned in mailing lists and newsgroups, people say they're really expensive.Let's examine that claim, shall we?

  • Creating multilingual websites - Part 1
    Extend the existing globalization capabilities of .NET to create flexible and powerful multilingual web sites. First, create a custom ResourceManager, and then create custom localized-capable server controls to easily deploy multilingual functionality.

  • Parameter passing in C#
    Many people have become fairly confused about how parameters are passed in C#, particularly with regard to reference types. This page should help to clear up some of that confusion

  • Most Popular Articles

  • LDAP, IIS and WinNT Directory Services
    This article explains how to use .NET Directory Services to retrieve and search directory objects, create new directory objects and edit or delete existing directory objects. Describes Active Directory Application Mode (ADAM) and how to use the IIS, WinNT and LDAP directory (ADSI) provider.

  • An in-depth look at WMI and instrumentation, Part II
    WMI stands for Windows Management Instrumentation and, as the name indicates, is about managing your IT infrastructure this article is the second part of a two-part series.

  • An in-depth look at WMI and instrumentation, Part I
    WMI stands for Windows Management Instrumentation and, as the name indicates, is about managing your IT infrastructure this article provides an in-depth look at WMI and MOM 2005

  • New Books

  • Murach's ASP.NET 2.0 Upgrader's Guide: VB Edition
    What’s new and how to use it! That’s what this book delivers if you’re a VB developer who’s interested in upgrading from ASP.NET 1.x to ASP.NET 2.0.

  • C# in easy steps
    Learn to program with Microsoft’s premier programming language. No previous programming knowledge is assumed. With numerous easy-to-follow examples, this title explains the essentials of object-oriented programming with C#.

  • Murach's ASP.NET web programming with VB.NET
    Murach's ASP.NET web programming with VB.NET by Doug Lowe and Anne Prince is a in depth training and reference book for ASP.NET programming using VB.NET. The book builds upon Murach's previous books and covers more advanced concepts for programming ASP.NET pages.

  • Got Code?

    if you have any article , source code , or anything else you'd like to share with this community that you think others might find useful, please submit it here and we will gladly make it available on this site. submit@developerland.com.
    Partners

    All articles are copyrighted by their individual authors unless otherwise specified , everything else Copyright ©2004-2006 DeveloperLand