Serializing data out to a file on WP7 is a very easy task thanks to the DataContractSerializer which allows you to tag properties in your class with '[DataMember]' and then use a few simple line of code to save/load that class to file:
1: // Save
2: MyClass theData = new MyClass();
3: using (IsolatedStorageFileStream fs = isoStore.OpenFile("MyClass.xml", FileMode.Create))
5: DataContractSerializer ser = new DataContractSerializer(typeof(MyClass));
6: ser.WriteObject(fs, theData);
9: // Load
10: using (IsolatedStorageFileStream fs = isoStore.OpenFile("MyClass.xml", FileMode.Open))
12: DataContractSerializer ser = new DataContractSerializer(typeof(MyClass));
13: MyClass result = (MyClass)ser.ReadObject(fs);
This is all well and good for getting something up and running quickly, but once you start having more complex classes and/or more data, performance starts to become an issue. A quick test of how long AppTracker currently takes to deserialize the cache file when following just 3 apps (Polyglot, Gifts and AppTracker - consisting of a total of about 544 reviews) resulted in the following timings:
|DataContractSerializer||Save Time (seconds)|
|DataContractSerializer||Load Time (seconds)|
As you will generally be loading up your data when the app loads (in a background thread and using a loading indicator I'd hope) the time it takes to load the data from file is noticeable to the user because it is the time between them launching the app and being able to actually use it.
Binary Serialization (Serialisation)
The DataContractSerializer stores data in the file in XML form which is one cause of the performance issues on larger/more complex datasets. Therefore it makes sense to use binary serialization instead, however WP7 doesn't have support for a Binary Serializer so you are left with two choices - Use a 3rd party library for Binary serialisation or Role your own!
This first post is going to cover 3rd Party solutions, and then later I will blog about creating your own.
After digging around on the net for a while I came across less information than I was hoping to find. A few places suggested using custom 'database' solutions but with SQL CE support coming for WP7 in the Mango update I decided to avoid that option. So in the end I was left with 2 possible solutions:
On it's website SharpSerializer is described as "an open source XML and binary serializer for .NET Framework, .NET Compact Framework and Silverlight" which sounds pretty good. It also offers a very simple interface making serializing just as easy as the DataContractSerializer, and can be dropped in place with little effort.
Unfortunately when I tried to just drop SharpSerializer into place I hit an exception and ultimately had to download the source and step through it to discover that if you have a class that implements the IEnumerable interface it must also implement the ICollection interface or you get an InvalidCastException. After fixing that issue I did the same timing tests as with the DataContractSerializer and got the following results:
|SharpSerializer||Save Time (seconds)|
|SharpSerializer||Load Time (seconds)|
As you can see the timings were in fact slightly slower, now this isn't to say that SharpSerializer is slow as I have seen a fair few sites show test data with results very different to these. What this test does show is that in my case SharpSerializer performs less well than DataContractSerializer, I'm not sure on the exact cause of that as I haven't yet ran it through a profiler to see if the issue is with the library or the objects I'm saving out (there's a good chance the issue could be on my side).
The other library that I found a few references to is called 'Silverlight Serializer' which is described on it's website as "a binary serializer that works in .NET and Silverlight, allowing you to move your objects between the two instances or store and retrieve them locally in either" and is created by Mike Talbot. This library also offers a simple interface allowing it to again be dropped into place with minimal effort. Unfortunately I once again hit some exceptions (this time a MissingMethodException and another one I've forgotten now), again potentially not the fault of the library and probably something I could have fixed with a bit of investigation.
However, at this point however I decided to give up and take a look at writing my own - Next blog post coming soon!
Update: The second part of this post is now here!