Click here to Skip to main content
15,889,096 members
Articles / Programming Languages / C#

A Fast/Compact Serialization Framework

Rate me:
Please Sign up or sign in to vote.
4.85/5 (37 votes)
13 Oct 2010GPL35 min read 282.3K   1.2K   175   97
A framework for object serializiation/deserialization that is many times faster and yields a compact output.

Introduction

NxSerialization is an easy to use object serialization framework that replaces the functionality of the default serialization providers for .NET and Mono. The binary formatter for NxSerialization can be up to 50 times faster than the default binary formatter for .NET and Mono. This is evident from the screenshot of the benchmark application shown above. There are three main benefits this framework provides to applications that serialize objects. The main benefits being that of increased space and time performance, and enhanced security comes as a byproduct.

Quick Facts

The figure below contains benchmark results using the sample application shipped with NxSerialization for CLI. The important values are given in bold. The time measured was for 100 iterations of 100 runs each. In each run, an object of the specified type was serialized and then deserialized. These results may vary depending upon the system configuration; however, the important thing to consider is the relative difference or the performance factors between the native and the NxSerializer.

Warning: These stats are from the previous release, and do not reflect comparison with latest native formatters.

Size based comparison of .NET and NxSerialization formatters

Size based comparison of .NET and NxSerialization formatters

Time based comparison of .NET and NxSerialization formatters

Time based comparison of .NET and NxSerialization formatters

What is New in 3.0?

There is nothing substantially new in this release, except the inclusion of the Remoting sub-system and a few unfinished features. After an extended long period of inactivity and quite some queries to release the Remoting specific portions, I have finally decided to release all that I had in my dev folders, and it's probably going to be the last release ever.

An interesting observation is that the latest versions of CLR have much improved native formatters, and what used to be on the average >5 times speed gain in the past is now much reduced. The stats above are therefore not representative of comparison with latest .NET versions. It also follows that the toolkit has probably seen its time :)

Unfinished Features

EAR - (Emit Avoid Reflection)

Some of the surrogates have an EAR property that when set uses dynamic IL to facilitate creation of objects and avoids the abhorred Activator.CreateInstance that is not known to be a super-fast way. The support is in early stages, and not rigorously tested, and therefore issues may popup. Moreover, there is no way to configure EAR externally, and source modifications are needed should you want to try it.

Remoting

The ability to use NxSerialization in Remoting sinks should theoretically speedup Remoting code - though the network latency may overshadow it - but surprisingly, the results have always been quite the opposite (which is why I never released it). There are also issues with HTTP channels (some functionality is missing), as well as Channel security that does not work at all.

Surrogates for System.Data.*

Still unimplemented - even though a straightforward task.

I would love to know if anyone still finds it useful and could spot the shortcomings in Remoting slowdown and suggest a fix. As always, your feedback is highly welcome!

Using the Framework

Application objects can be integrated with the framework in two ways. By writing a surrogate for the object type and registering the surrogate with the framework, or by implementing INxSerializable. The framework provides a built-in surrogate for types that implement INxSerializable. For unknown types, native .NET serialization is used.

The following sample of code demonstrates a type that implements INxSerializable. Note the line at the bottom that registers the type with the framework.

C#
// Sample class that implements INxSerializable
[Serializable]
class SampleCompactableClass : INxSerializable
{
   private String title = "SampleCompactableClass";

   void INxSerializable.Serialize(INxBinaryWriter w)
   {
      w.Write(title);
   }

   void INxSerializable.Deserialize(INxBinaryReader r)
   {
      title = r.ReadString();
   }
}

...
// Register the class with the framework.
NxFormatterServices.Default.RegisterKnownType(typeof(SampleCompactableClass));

The following sample of code demonstrates a sample surrogate for another type that does not implement INxSerializable. Using surrogates is the only way the framework is able to compactly serialize .NET native types.

C#
// Sample surrogate for SampleSurrogatedClass
class SampleSurrogate : NxSerializationSurrogate
{
   public SampleSurrogate() : base(typeof(SampleSurrogatedClass)) {}

   public override object Read(INxBinaryReader r)
   {
      SampleSurrogatedClass obj = new SampleSurrogatedClass();
      obj.title = r.ReadString();
      return obj;
   }

   public override void Write(INxBinaryWriter w, object graph)
   {
      SampleSurrogatedClass obj = (SampleSurrogatedClass) graph;
      w.Write(obj.title);
   }
}

// Sample class that does not implement INxSerializable
[Serializable]
class SampleSurrogatedClass
{
   internal string title = "SampleSurrogatedClass";
}

...
// Register the surrogate with the framework.
NxTypeSurrogateSelectorNative.Default.Register(new SampleSurrogate());

Everything else is pretty much self-explanatory. For more information, look at the sample benchmark application provided with the source code.

Comments

Please note that for objects where the actual data size to type-info size ratio is very large, not much memory reduction will occur. Try a byte array of size 100K. It is also possible to come up with a case where the native serializer is actually more efficient in terms of CPU.

Among other possibilities with the framework are:

  • Enhanced security as custom serialization protects your object's data from prying eyes. Excluding the possibilities of complete reverse engineering, objects cannot be deserialized from persistent streams.
  • .NET CLR 1.x objects can be deserialized into 2.0 objects. Objects of type A can be deserialized to objects of type B etc.

History

OpenNxSerialization 2.0 (August 08, 2008)

Changes in this version include:

  • Arrays and collections serialization is now significantly faster.
  • New surrogates for a lot of built-in types.
  • Support for serialization of containers in the System.Collections.Generic namespace.
  • Support for serialization of BitVector32, BitArray and KeyValuePair objects.
  • Support for serialization of Type objects.
  • Surrogate redirection support now provided.
  • Dynamic (on the fly) surrogates now supported.
  • Major refactoring of the API.
  • Quite a few enhancements and utilities everywhere.

OpenNxSerialization 1.5 (March 12, 2008)

Changes in this version include:

  • NxFormatter now implements IRemotingFormatter.
  • New surrogates for a lot of built-in types.
  • Support for serialization of ISerializable objects.
  • Support for serialization of MarshalByRef objects.
  • Support for generic versions of SerializeAs and DeserializeAs functions.
  • Streaming context can now contain application specific items.
  • Quite a few enhancements and utilities everywhere.

OpenNxSerialization 1.0 (CompactSerialization 2.5) (July 21, 2007)

Once again, thanks to all contributors. Changes in this version include:

  • CompactSerialization 2.5 is now OpenNxSerialization 1.0.
  • Support for multiple instances of TypeSurrogateSelector.
  • Support for SerializeAs and DeserializeAs functions (faster and more compact).
  • Reader does not close the base stream.
  • Support to configure types using a config file.
  • Quite a few enhancements and utilities everywhere.

CompactSerialization 2.0 (May 17, 2006)

This has been possible due to the wonderful feedback I've received. Thanks to all contributors. Changes in this version include:

  • Support for .NET 2.0 Nullable types.
  • Circular and shared references are now handled wisely.
  • Support for permanent/hard type handles.
  • Support for enumerations, SortedList etc.
  • Major refactoring of the internal and public APIs.
  • Improved performance at places, and decreased at places :).

CompactSerialization 1.0 (Feb 15, 2006)

  • Released the initial version of the framework.

License

This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)


Written By
Architect
Pakistan Pakistan
Let a = b ....... (1)
a - b = a - b
a^2 - ab = a^2 - ab
a^2 - ab = a^2 - b^2 (from 1)
a (a - b) = (a + b) (a - b)
a = (a + b) ...... (2)

if a = 1
1 = (1 + 1) (from 1 & 2)
1 = 2 !!

Comments and Discussions

 
GeneralRe: Idea to use attribute-based serialization without performance loss Pin
rkagerer24-Jul-06 0:44
rkagerer24-Jul-06 0:44 
GeneralRe: Idea to use attribute-based serialization without performance loss Pin
.Shoaib24-Jul-06 20:01
.Shoaib24-Jul-06 20:01 
GeneralRe: Idea to use attribute-based serialization without performance loss Pin
rkagerer24-Jul-06 20:39
rkagerer24-Jul-06 20:39 
GeneralRe: Idea to use attribute-based serialization without performance loss Pin
.Shoaib26-Jul-06 19:37
.Shoaib26-Jul-06 19:37 
GeneralRe: Idea to use attribute-based serialization without performance loss Pin
rkagerer27-Jul-06 2:08
rkagerer27-Jul-06 2:08 
GeneralRe: Idea to use attribute-based serialization without performance loss [modified] Pin
Mars Warrior25-Jul-06 5:47
Mars Warrior25-Jul-06 5:47 
AnswerRe: Idea to use attribute-based serialization without performance loss Pin
.Shoaib23-Jul-06 23:55
.Shoaib23-Jul-06 23:55 
GeneralReference resolving Pin
igor_shubovych29-Mar-06 19:58
igor_shubovych29-Mar-06 19:58 
Pretty nice framework. I desided to use it in my project.
But it has one issue. What if object A has reference to object B, and object B has reference to object A? The example you considered is just particular case. What if object A doesn't know what child it contains?

So I had to write some things which will store reference, not the whole object. I add some new functionality to the ICompactSerializableSerializationSurrogate and CompactBinaryFormatter.

The core idea is:
* when we serialize object we will also its hashcode and store it in cache;
* if we try to serialize object which is in cache, surrogate will save only hashcode;
* when we deserialize object we read hashcode and then if it has already been deserialized (it is in cache), we read it from cache, otherwise we read it and put in cache.

CompactBinaryFormatter now contains new object cache.
<br />
    internal static Dictionary<int, object> cache = new Dictionary<int, object>();<br />
<br />
    public static void ClearCache()<br />
    {<br />
        cache.Clear();<br />
    }<br />
<br />


Functionality of object surrogate also changed.
<br />
	public override object Read(CompactBinaryReader reader)<br />
	{		<br />
            int key = reader.ReadInt32();<br />
            if (CompactBinaryFormatter.cache.ContainsKey(key))<br />
                return CompactBinaryFormatter.cache[key];<br />
            else<br />
            {<br />
                ICompactSerializable graph = (ICompactSerializable)CreateInstance();<br />
                CompactBinaryFormatter.cache[key] = graph;<br />
                graph.Deserialize(reader);<br />
                return graph;<br />
            }<br />
	}<br />
<br />
	public override void Write(CompactBinaryWriter writer, object graph)<br />
	{<br />
            int key = graph.GetHashCode();<br />
            writer.Write(key);<br />
            if (!CompactBinaryFormatter.cache.ContainsKey(key))<br />
            {<br />
                CompactBinaryFormatter.cache[key] = graph;<br />
                ((ICompactSerializable)graph).Serialize(writer);<br />
            }<br />
        }<br />

GeneralNew useful functionality Pin
igor_shubovych30-Mar-06 3:04
igor_shubovych30-Mar-06 3:04 
AnswerRe: New useful functionality Pin
.Shoaib9-Apr-06 18:32
.Shoaib9-Apr-06 18:32 
NewsRe: New useful functionality Pin
.Shoaib17-May-06 20:15
.Shoaib17-May-06 20:15 
GeneralRemoting Pin
eliadinbar19-Mar-06 10:14
eliadinbar19-Mar-06 10:14 
AnswerRe: Remoting Pin
.Shoaib19-Mar-06 18:24
.Shoaib19-Mar-06 18:24 
GeneralGreat but with one disadvantage Pin
Misha Zhutov10-Mar-06 2:58
Misha Zhutov10-Mar-06 2:58 
AnswerRe: Great but with one disadvantage Pin
.Shoaib19-Mar-06 18:26
.Shoaib19-Mar-06 18:26 
NewsRe: Great but with one disadvantage Pin
.Shoaib17-May-06 20:13
.Shoaib17-May-06 20:13 
Generala bug Pin
eliadinbar7-Mar-06 1:16
eliadinbar7-Mar-06 1:16 
AnswerRe: a bug Pin
.Shoaib8-Mar-06 17:02
.Shoaib8-Mar-06 17:02 
NewsRe: a bug Pin
.Shoaib17-May-06 20:14
.Shoaib17-May-06 20:14 
General.Net 2.0 Pin
eliadinbar5-Mar-06 7:20
eliadinbar5-Mar-06 7:20 
GeneralRe: .Net 2.0 Pin
.Shoaib5-Mar-06 18:02
.Shoaib5-Mar-06 18:02 
GeneralRe: .Net 2.0 Pin
eliadinbar5-Mar-06 20:43
eliadinbar5-Mar-06 20:43 
GeneralRe: .Net 2.0 Pin
.Shoaib6-Mar-06 21:31
.Shoaib6-Mar-06 21:31 
GeneralRe: .Net 2.0 Pin
eliadinbar6-Mar-06 22:52
eliadinbar6-Mar-06 22:52 
GeneralAnother way Pin
leppie22-Feb-06 22:27
leppie22-Feb-06 22:27 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.