Click here to Skip to main content
15,867,308 members
Articles / Mobile Apps / Windows Mobile

Binary Serialization to Isolated Storage in Silverlight - BinaryFormatter vs. sharpSerializer

Rate me:
Please Sign up or sign in to vote.
4.82/5 (7 votes)
6 Oct 2010CPOL5 min read 126.1K   804   20   32
How to serialize binary data to IsolatedStorage in a Silverlight client when there is no BinaryFormatter in Silverlight? Why not with sharpSerializer? - An open source XML and binary serializer for .NET and Silverlight

Introduction

A Silverlight application has by default 1MB of available space in the isolated storage to store its local data. If started as an "out of browser" window, this amount increases to 25MB, even if the application has no elevated permissions. You can check the free memory amount by pressing the right mouse button on your Silverlight program, then go to the registry "Application storage" and there you see it.

Unfortunately sometimes there is more storage needed. For example - a briefcase model - a sales agent downloads data from the server, works offline with the data by a customer, and finally synchronizes the data with the server.

You can always demand more free space for the application using the method IncreaseQuotaTo() of the IsolatedStorageFile class, as described in the following article:

However increasing only the storage size is not optimal. A better solution would be saving the data more efficiently than to XML.

Background

DataContractSerializer is a standard way of serializing business objects by a Silverlight client. But it serializes to XML which is known as a wasteful way of storing data. A better choice would be a binary serialization. But there is a problem - there is no BinaryFormatter in Silverlight at all. :-(

A third-party software is needed. Let's take for example sharpSerializer - an open source XML and binary serializer for .NET, .NET Compact and Silverlight - and compare it with BinaryFormatter from the full .NET Framework.

BinaryFormatter vs. sharpSerializer

As I said before - there is no BinaryFormatter in Silverlight. To get some results anyway, I checked the serialization speed and output file size of BinaryFormatter from the full version of .NET Framework and compared these values with the results of sharpSerializer v.2.6.

Serialized was an array of 10.000 elements of type RootContainer - a very sophisticated sample class from the HelloWorldDemo of sharpSerializer. I had to mark the RootContainer and all of its subclasses with [Serializable] as it's demanded by BinaryFormatter to work. Btw, SharpSerializer needs no additional attributes in serialized objects, nor any type definitions in its Serialize() method, as i.e. XmlSerializer needs.

Below you see the main body of the RootContainer. To see all of its subclasses, refer to the source code of sharpSerializer (There is another article describing serialization of weird classes like the RootContainer to XML - XML Serialization of Generic Dictionary, Multidimensional Array, and Inherited Type, with sharpSerializer .NET).

C#
// This is an example from the http://www.sharpserializer.com
// Please download the full source code with HelloWorld demo to see more details.
[Serializable]
public class RootContainer
{
    public SByte SimpleSByte { get; set; }
    public int SimpleInt { get; set; }
    public Single SimpleSingle { get; set; }
    public double SimpleDouble { get; set; }
    public DateTime SimpleDateTime { get; set; }
    public TimeSpan SimpleTimeSpan { get; set; }

    /// Every enumeration is simple type
    public SimpleEnum SimpleEnum { get; set; }

    /// Enumeration with FlagsAttribute is SimpleType.
    /// It is correct serialized if the result of the flag combination 
    /// has unique int value,
    /// i.e. Flag1 = 2, Flag2 = 4, Flag3 = 8 ...
    public FlagEnum FlagsEnum { get; set; }

    /// Decimal is 16 bytes long
    public decimal SimpleDecimal { get; set; }
    public string SimpleString { get; set; }
    public string EmptyString { get; set; }

    /// Structures are handled as objects during serialization
    /// They are serialized as ComplexProperty
    public AdvancedStruct AdvancedStruct { get; set; }

    /// One dimensional array of simple type.
    /// It is serialized as SingleDimensionalArrayProperty
    public string[] SingleArray { get; set; }

    /// Multidimensional array of simple type.
    /// Is is serialized as MultiDimensionalArrayProperty
    public string[,] DoubleArray { get; set; }

    /// Single array of derived objects.
    /// This is polymorphic collection - Items derive from the interface
    public IComplexObject[] PolymorphicSingleArray { get; set; }

    /// Generic list is serialized as a collection.
    /// It is serialized as CollectionProperty
    public IList<string> GenericList { get; set; }

    /// Generic Dictionary of simple types.
    /// Is is serialized as DictionaryProperty
    public IDictionary<int, string> GenericDictionary { get; set; }

    /// Generic dictionary where values are inherited from the value type
    public IDictionary<int, 
	IComplexObject> GenericDictionaryOfPolymorphicValues { get; set; }

    /// Polymorphic property. Object instance derives from the property type
    /// Is serialized as ComplexProperty
    public IComplexObject ComplexObject { get; set; }

    /// Collection where item values are
    /// derived from the collection item type
    public ComplexObjectPolymorphicCollection ComplexObjectCollection { get; set; }

    /// Dictionary where values are derived
    /// from the predefined dictionary value type
    public ComplexObjectPolymorphicDictionary ComplexObjectDictionary { get; set; }

    /// List items are derived from the generic attribute.
    /// This is polymorphic attribute.
    public IList<IComplexObject> GenericListOfComplexObjects { get; set; }

    /// Generic object with polymorphic attribute.
    /// It is serialized as ComplexProperty
    public GenericObject<IComplexObject> GenericObjectOfComplexObject { get; set; }

    /// Multidimensional array of generic object with polymorphic attribute
    public GenericObject<IComplexObject>[,] 
	MultiArrayOfGenericObjectWithPolymorphicArgument { get; set; }

    /// Array of objects where every item can be of other type
    /// It is serialized as SingleDimensionalArrayProperty
    public object[] SingleArrayOfObjects { get; set; }
}

For testing purposes, I made a small benchmark console program to measure the serialization and deserialization time and to store the serialization results as files - to compare their sizes.

The "Main" method produces 10.000 elements of the RootContainer and invokes single test methods:

C#
static void Main(string[] args)
{
    // create 10.000 items
    RootContainer[] containerArray = createContainerArray(10000);

    // Serialization tests
    Console.WriteLine("Serializing");
    serializeWithBinaryFormatter(containerArray, "BinaryFormatter.bin");
    serializeWithSharpSerializer(containerArray, 
	BinarySerializationMode.Burst, "sharpSerializerBurst.bin");
    serializeWithSharpSerializer(containerArray, 
	BinarySerializationMode.SizeOptimized, "sharpSerializerOptimized.bin");
    serializeWithXmlSharpSerializer(containerArray, "sharpSerializer.xml");

    // Deserialization tests
    Console.WriteLine();
    Console.WriteLine("Deserializing");
    deserializeWithBinaryFormatter("BinaryFormatter.bin");
    deserializeWithSharpSerializer(BinarySerializationMode.Burst, 
				"sharpSerializerBurst.bin");
    deserializeWithSharpSerializer(BinarySerializationMode.SizeOptimized, 
				"sharpSerializerOptimized.bin");
    deserializeWithXmlSharpSerializer("sharpSerializer.xml");
}

The following method uses BinaryFormatter for the serialization. Note! Stopwatch is the most adequate class in .NET to measure time.

C#
private static void serializeWithBinaryFormatter
	(RootContainer[] containerArray, string shortFilename)
{
    // convert short filename to full filename
    string filename = getFilename(shortFilename);

    // creating a stream, as BinaryFormatter can not serialize directly to a file
    using (var stream = new FileStream(filename, FileMode.Create))
    {
        var formatter = new BinaryFormatter();

        // Stopwatch <span lang="de">as a stopper is enough accurate</span>
        Stopwatch watch = new Stopwatch();
        Console.WriteLine("Starting serialization with BinaryFormatter");
        watch.Start();

        // Serializing
        formatter.Serialize(stream, containerArray);

        watch.Stop();
        Console.WriteLine(string.Format
		("Stopped after {0}ms", watch.ElapsedMilliseconds));
    }
}

To serialize the test object with sharpSerializer, I created the following method. Btw, SharpSerializer has much easier syntax than BinaryFormatter.

C#
private static void serializeWithSharpSerializer
    (RootContainer[] containerArray, BinarySerializationMode mode, string shortFilename)
{
    string filename = getFilename(shortFilename);

    // create sharpSerializer with an overloaded constructor
    var serializer = new SharpSerializer(mode)

    Stopwatch watch = new Stopwatch();
    Console.WriteLine(string.Format("Starting serialization with SharpSerializer ({0})", 
		Enum.GetName(typeof(BinarySerializationMode), mode)));
    watch.Start();

    // Serializing
    serializer.Serialize(containerArray, filename);

    watch.Stop();
    Console.WriteLine(string.Format("Stopped after {0}ms", watch.ElapsedMilliseconds));
}

Serialization and deserialization times on the program screen:

Serialization and deserialization times

Serialization and deserialization results in a table (For serializing of other objects, the results and their proportions can vary):

SerializerSerialization time [s]File size [MB]Deserialization time [s]
.NET BinaryFormatter2.119.37.9
sharpSerializer - binary (Burst)3.13.83.7
sharpSerializer - binary (SizeOptimized)3.88.52.6
sharpSerializer - XML3.786.017.6

The fastest serialization of 2.1s offers BinaryFormatter, but its file size of 19.3MB is twice as big as produces sharpSerializer in its binary SizeOptimized mode (you can find more about binary modes of sharpSerializer in the tutorial on the project page).

The deserialization time of BinaryFormatter is over 3 times longer than the best time 2.6s of sharpSerializer.

Result Analysis

Server Side

Where the full .NET Framework is available, you have a choice between BinaryFormatter and sharpSerializer to make a binary serialization. If you write data only once and read it multiple times (i.e. photo gallery or an mp3 music store) - then sharpSerializer is a better choice than the built-in BinaryFormatter. It stores 80% slower but reads 300% faster then BinaryFormatter. Not to mention the file size which is 50% smaller if serialized with sharpSerializer.

Silverlight Client Side

In Silverlight, there is no choice if you want to use binary serialization. As there is no BinaryFormatter in Silverlight, the only solution is sharpSerializer.

Advantages of sharpSerializer

  • Very easy syntax
  • No need to mark the serialized object with additional attributes
  • No need to declare serialized types in the Serialize() method
  • Small size of the produced file
  • Fast deserialization of objects
  • Common algorithm and serialization compatibility between .NET Full, .NET Compact and Silverlight
  • Open Source and free for any purpose

Disadvantages of sharpSerializer

  • Only public properties are serialized
  • Only objects with standard constructor are deserialized
  • XML and binary format is not compatible with other .NET standards

Conclusion

Among many advantages and good benchmarks, there are also some disadvantages of sharpSerializer. It depends on the context, if the disadvantages are a stone in the shoe.

As I use sharpSerializer mostly to store my own business objects, there is no problem for me to provide a standard constructor for every object. There is also no problem in using only public properties to store the object's state.

If there are complicated third-party classes to serialize, they should be converted with an adapter pattern into simple ones. The adapter pattern simplifies the output and decreases its size in most cases, as only needed properties are serialized.

sharpSerializer is no more Beta, its current version is 2.6. It works stable and reliable.

One of the future milestones of sharpSerializer is data compression. Actually there are problems with finding an open source substitute for DeflateStream for Silverlight as GZipStream and DeflateStream are not supported in Silverlight 4 and earlier versions. After the data compression is implemented, the list with advantages of sharpSerializer can be extended with a point "very, very small size of the produced file". :-)

From the Author

There is another article about XML serialization with sharpSerializer:

Of course, you are encouraged to make your own tests with sharpSerializer Framework. If you like this article, please rate it, if not - tell me why in the comment field below. ;-)

History

  • October 6, 2010 - First release

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Polenter - Software Solutions
Germany Germany
I'm C# developer from Cologne, Germany. Here I owe a small software company. My hobby is general optimization - natural talent of all lazy people Wink | ;-)

Comments and Discussions

 
Questionhelp me ,please. Pin
huzhenglin3-Oct-14 0:27
huzhenglin3-Oct-14 0:27 
AnswerRe: help me ,please. Pin
Pawel idzikowski3-Oct-14 2:01
Pawel idzikowski3-Oct-14 2:01 
QuestionAlternative to Reflection Pin
kiquenet.com21-Oct-13 20:37
professionalkiquenet.com21-Oct-13 20:37 
GeneralOne more question Pin
Dewey18-Nov-10 9:17
Dewey18-Nov-10 9:17 
GeneralRe: One more question - some success Pin
Dewey18-Nov-10 9:38
Dewey18-Nov-10 9:38 
GeneralRe: One more question - some success Pin
Pawel idzikowski18-Nov-10 10:13
Pawel idzikowski18-Nov-10 10:13 
GeneralRe: One more question - some success Pin
Dewey18-Nov-10 12:28
Dewey18-Nov-10 12:28 
GeneralRe: One more question - Complete success Pin
Dewey18-Nov-10 12:40
Dewey18-Nov-10 12:40 
GeneralSend binary to server Pin
Dewey17-Nov-10 21:08
Dewey17-Nov-10 21:08 
GeneralRe: Send binary to server Pin
Pawel idzikowski18-Nov-10 6:24
Pawel idzikowski18-Nov-10 6:24 
GeneralRe: Send binary to server Pin
Dewey18-Nov-10 9:02
Dewey18-Nov-10 9:02 
NewsBusiness Applications Guru Max Dolgicer Speaks at India's Most Influential Business Technology Event Pin
swagat barman24-Oct-10 19:51
swagat barman24-Oct-10 19:51 
GeneralSilverlight Serializer performance in your test harness Pin
michael_john_talbot9-Oct-10 1:47
michael_john_talbot9-Oct-10 1:47 
GeneralRe: Silverlight Serializer performance in your test harness Pin
Pawel idzikowski9-Oct-10 3:15
Pawel idzikowski9-Oct-10 3:15 
GeneralRe: Silverlight Serializer performance in your test harness Pin
michael_john_talbot9-Oct-10 3:32
michael_john_talbot9-Oct-10 3:32 
GeneralRe: Silverlight Serializer performance in your test harness Pin
michael_john_talbot9-Oct-10 6:02
michael_john_talbot9-Oct-10 6:02 
GeneralRe: Silverlight Serializer performance in your test harness Pin
Pawel idzikowski9-Oct-10 10:07
Pawel idzikowski9-Oct-10 10:07 
I give up. there is type caching in my framework but further caching is not possible unless I refactor the whole system. In your Serializer there are only two layers - reading and object creating. in mine there are three - reading, creating internal properties, and creating objects from these properties. it's easier to read for a newbie but it's just heavier. checksum control is so easy but genial and this amazing ThreadStaticAttribute, You've used an alien technology... OMG | :OMG:
GeneralRe: Silverlight Serializer performance in your test harness Pin
michael_john_talbot9-Oct-10 11:25
michael_john_talbot9-Oct-10 11:25 
GeneralRe: Silverlight Serializer performance in your test harness Pin
michael_john_talbot5-Aug-11 10:28
michael_john_talbot5-Aug-11 10:28 
General[Serializable] and [ExcludeFromSerialization] Pin
Paulo Zemek7-Oct-10 5:25
mvaPaulo Zemek7-Oct-10 5:25 
GeneralRe: [Serializable] and [ExcludeFromSerialization] Pin
Pawel idzikowski7-Oct-10 9:41
Pawel idzikowski7-Oct-10 9:41 
GeneralRe: [Serializable] and [ExcludeFromSerialization] Pin
Paulo Zemek7-Oct-10 12:58
mvaPaulo Zemek7-Oct-10 12:58 
GeneralRe: [Serializable] and [ExcludeFromSerialization] Pin
Pawel idzikowski7-Oct-10 19:59
Pawel idzikowski7-Oct-10 19:59 
QuestionCould you briefly detail how it works internally? Pin
I'm Chris7-Oct-10 4:45
professionalI'm Chris7-Oct-10 4:45 
AnswerRe: Could you briefly detail how it works internally? Pin
Pawel idzikowski7-Oct-10 5:18
Pawel idzikowski7-Oct-10 5:18 

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.