Create a Snapshot of your data in Silverlight

I’ve been working on some Silverlight projects with a designer and in a word – it’s been fantastic. Alex, my brother, and I have been learning Silverlight 2 together. It’s been a great way to figure out what works best in our little Silverlight
team.

Silverlight separates concerns between me, the developer and the designer very well. I love being able to throw a design issue over to Alex to fix. He does a “get latest”, runs it up and fixes the issue/makes the app look _not_ crap.

This is all good, until the application gets a little more complex. I add WCF services, databases and other technical dependencies which require some level of set up. Alex is quite technical, but some of these things sit outside the scope of his professional experience. This leads to a problem where we sit on the phone for an hour trying to figure out why it’s not working. “Works on my machine” seal doesn’t apply here unfortunately.

So what do you do?

There are a range of ways to fix a problem like this. One way is to use dummy test data. Put the application in to “dummy” mode and load the data from another source rather than your WCF service etc.

This means that your designers can press F5 and have the application “just work” – a pretty ideal situation you have to admit. This solution is also great for sales demonstrations – keeping a sales person’s notebook up to date with the latest website version, WCF, database etc is a PITA 🙂 I don’t know how many times I’ve been caught before a big demo fixing the demo notebook because it has some arcane issue that never seems to occur on any other notebook I’ve ever used.

The problem then becomes – how to you get _good_ dummy data? You really don’t want to be creating this by hand… Why not set your model classes up in a way that you can take a snapshot of them and re-load it in dummy mode?

This is actually pretty easy to achieve by using the DataContractSerializer class which is built in to Silverlight.

The process overview is:

  • Design model classes in a way that supports DataContractSerialization
  • Apply DataContract attributes to the classes
  • Serialise the object graph to ISO storage
  • Find the file on the hard drive and copy in to Silverlight project
  • Add a setting to place the project in to “dummy” mode
  • Load the serialised object from the XAP (it will be compiled in)
  • Enjoy a problem free relationship with your designer 🙂

<Sample Code>

Serialise your Silverlight Object Graph Example

</Sample Code>

Preparing for Serialisation

There are a couple of simple rules when performing serialisation in Silverlight using DataContractSerializer.

  • In partial trust (which Silverlight runs in) you can only serialise public fields
  • It’s easiest to serialise object graphs which do not have circular dependencies

With these two rules in mind let’s smash together some code.

  • Create a new Silverlight project
  • Create some simple demonstration model classes
  • Create Serialize and Deserialize methods
  • Manually populate with test data (normally this would be some real database data)
  • Serialize data, get file, copy to project and set up for deserialization

When creating a serializable data model ensure you have one starting point. That is a main object which is the root of the object graph. Ensure that you have no circular dependencies.

  • Create two simple classes called ModelMainClass and SomeOtherClass
  • Add a couple of simple properties to ModelMainClass
  • Add a couple of simple properties to SomeOtherClass
  • Add a reference to System.Runtime.Serialization
  • Decorate each class with [DataContract] attribute
  • Decorate the properties and member variables in each class you want to serialise with the [DataMember] attribute
  • Add a List property to ModelMainClass to hold references to instances of SomeOtherClass. Ensure it is also marked with the DataMemberAttribute

[DataContract]
public class ModelMainClass
{
	[DataMember]
	public string SomeProperty
	{
		get;
		set;
	}

	[DataMember]
	public long SomeValue
	{
		get;
		set;
	}
	[DataMember]
	public List SomeOtherClassInstances
	{
		get;
		set;
	}
}

[DataContract]
public class SomeOtherClass
{
	[DataMember]
	public string SomeOtherClassValue
	{
		get;
		set;
	}
}

Get the data in to isolated storage

Next up we need to create the serialisation and deserialisation class.

Create a new file called Persistence.cs

This file will have the following functionality

  • A method to serialise to a byte array
  • A method to deserialise from a byte array
  • A method to write a byte array to isolated storage
  • For posterity a method to read a byte array from isolated storage
  • A method to read a byte array from the XAP file
const string PERSISTFILENAME = "persist.dat";

static List knownTypes = null;

public static void ISOSave(ModelMainClass mmc)
{
	try
	{
		MemoryStream ms = new MemoryStream();

		DataContractSerializer ser = new DataContractSerializer(mmc.GetType(), getKnownTypes());

		ser.WriteObject(ms, mmc);

		byte[] data = ms.ToArray();
		commit(data);
	}
	catch (Exception ex)
	{
		Console.WriteLine("Argh");
	}
}

static void commit(byte[] data)
{
	using (IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication())
	{
		IsolatedStorageFileStream isfs = new IsolatedStorageFileStream(PERSISTFILENAME, FileMode.Create, isf);

		isfs.Write(data, 0, data.Length);

		isfs.Close();
	}
}

static byte[] load(bool dummyData)
{
	if (dummyData)
	{
		StreamResourceInfo s = Application.GetResourceStream(new Uri("MockData/persisted.dat", UriKind.Relative));

		byte[] result = new byte[s.Stream.Length];
		s.Stream.Read(result, 0, result.Length);
		s.Stream.Close();
		return result;
	}
	else
	{
		using (IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication())
		{
			if (isf.FileExists(PERSISTFILENAME))
			{
				IsolatedStorageFileStream isfs = new IsolatedStorageFileStream(PERSISTFILENAME, FileMode.Open, isf);

				byte[] result = new byte[isfs.Length];
				isfs.Read(result, 0, Convert.ToInt32(isfs.Length));
				isfs.Close();
				return result;
			}
			else
			{
				return null;
			}
		}
	}
}

public static ModelMainClass ISOLoad(bool dummyData)
{
	byte[] data = load(dummyData);
	
	if (data == null)
	{
		return new ModelMainClass();
	}
	else
	{
		DataContractSerializer ser = new DataContractSerializer(typeof(ModelMainClass), getKnownTypes());
		MemoryStream ms = new MemoryStream(data);
	   
		ModelMainClass mmc = ser.ReadObject(ms) as ModelMainClass;
		return mmc;
	}

}

private static List getKnownTypes()
{
	if (knownTypes == null)
	{
		knownTypes = new List();
		knownTypes.Add(typeof(SomeOtherClass));
		knownTypes.Add(typeof(ModelMainClass));               
	}
	return knownTypes;

}

Note here the Load method has the ability to load data from isolated storage and from the dummy data in the XAP. This is for posterity and completeness 🙂

Generate some test data

In Page.xaml create a button to create and save the test data. In the button’s Click even drop in the following code:


ModelMainClass mmc = new ModelMainClass();

mmc.SomeProperty = string.Format("This is a test {0}", DateTime.Now.ToString());
mmc.SomeValue = DateTime.Now.Ticks;

List list = new List();

for (int i = 0; i < 100; i++)
{
	list.Add(new SomeOtherClass() { SomeOtherClassValue = i.ToString() });
}

mmc.SomeOtherClassInstances = list;

Persistence.ISOSave(mmc);

Pretend this code is getting some stuff from your WCF service etc. Serialise your completed object graph here.

Note the call to Persistence.ISOSave which is our new method…

Find the data in isolated storage

Silverlight keeps its isolated storage underneath the user’s data folder.

On Vista look under here: C:\Users\<user>\AppData\LocalLow\Microsoft\Silverlight\is
On XP look under here: C:\Documents and Settings\<user>\Local Settings\Application Data\Microsoft\Silverlight\is

You will need to have a bit of a hunt around in these folders to find what you are looking for (search doesn’t seem to work). For example on my machine the file was located here:

C:\Users\jordank\AppData\LocalLow\Microsoft\Silverlight\is\tuigc5pi.rqh\xhfonuik.kdv\1\s\rqotqem0g1s0rro4dxwbnvcvci50t01b4knyscivinuy3ejenraaaeda\f.

Nice.

Copy this file in to your Silverlight project, and set it’s Build Action to “Content”. Setting this to content allows the Persistence class to read the data using the following code:

StreamResourceInfo s = Application.GetResourceStream(new Uri("MockData/persisted.dat", UriKind.Relative));

Finishing off

Back in Page.xaml, create another button to load the data, and a TextBlock to proove the load worked. In the click event for the button drop the following code:

ModelMainClass mmc = Persistence.ISOLoad(true);
foreach (SomeOtherClass soc in mmc.SomeOtherClassInstances)
{
	SomeOutput.Text += soc.SomeOtherClassValue;
}

Too easy! You just loaded your snapshot from the XAP file!

You can see how easy it would be to build complex dummy data object graphs and distribute them with your application.

And everyone lives happily ever after

28 thoughts on “Create a Snapshot of your data in Silverlight

  1. Become active Absorption, the favorite for?Someone that can, offered by Hosting.From smoking-related illnesses, refinancing loan is.To change Hypnosis zahnimplantaten, culture – its This Kuan Yin.Course Not only, a different reality.,

  2. Pingback: get ultimate demon
  3. Pingback: pastoral resources
  4. Pingback: [link]

Comments are closed.