Introduction
When developing a Silverlight application you may want to save certain user or environment specific information for each of your users. Sure you can do this with cookies, but there's something better: isolated storage.
What is Isolated Storage?
Isolated storage is a file-based storage mechanism where data is always isolated by user and assembly. Data is stored on the client-side and such specifics as file location and disk quota are managed by the isolated storage framework (although there is some room for customization).
In short, isolated storage is like having your own private playground for data storage for your Silverlight apps.
What are the advantages of Isolated Storage over Cookies?
- cookies are limited to 4kb in size. Not so with Isolated Storage (though there are file system type space limitations)
- data saved to Isolated Storage is not stored in the browser's cache like a cookie and is therefore not wiped out when a user clears their cache
Implementing Isolated Storage - Setup
I'm going to demonstrate how to save and retrieve information from isolated storage from within a Silverlight application. In order to get to the "good" stuff right away, I'm going to skip over setting up the sample app and instead refer you to the source linked at the bottom of this post. The end result is you'll have a Silverlight app that looks like this with the needed static resources and event handler already in place:
You'll see that the sample application contains methods to save and load user info as well as an event handler tied to the "Save Info" button. The event handler simply calls into the save method, so let's look more specifically at loading and saving user info since that's where we touch isolated storage.
Saving Data to Isolated Storage
The needed namespaces are already defined in Page.xaml.cs:
1: using System.IO;
2: using System.IO.IsolatedStorage;
3: using System.Xml.Linq;
The first two are necessary for basic isolated storage access. System.Xml.Linq is there because I'm using LINQ-to-XML to save and retrieve data to our isolated storage file.
Here's the basic skeleton that we'll use to save data to isolated storage:
1: private void SaveUserInfo()
2: {
3: return;
4: }
5:
6: private void btnSaveInfo_Click (object sender, RoutedEventArgs e)
7: {
8: SaveUserInfo ();
9:
10: return;
11: }
Pretty basic. We have an event handler tied to the "Save Info" button that calls into the "SaveUserInfo()" method. Here's the code we need to save name, web site, and email to a file using isolated storage and LINQ-to-XML:
1: private void SaveUserInfo()
2: {
3: var doc = new XDocument (
4: new XElement ("UserInfo",
5: new XElement ("Name", tbxName.Text),
6: new XElement ("WebSite", tbxWebSite.Text),
7: new XElement ("Email", tbxEmail.Text)
8: )
9: );
10:
11: using (var isoStore = IsolatedStorageFile.GetUserStoreForApplication ())
12: {
13: using (var isoStream = new IsolatedStorageFileStream ("UserInfo.xml", FileMode.Create, isoStore))
14: {
15: doc.Save (isoStream);
16: }
17: }
18:
19: return;
20: }
On Lines 3-9, we create a new XDocument to hold our XML data using the textbox controls named tbxName, tbxWebSite, and tbxEmail to provide the user's info. Next, on Line 11, we gain access to isolated storage using the IsolatedStorageFile class. On Line 13 we create an isolated storage stream via IsolatedStorageFileStream, creating the file "UserInfo.xml". Finally, on Line 15, we use LINQ-to-XML to save the data to the file stream.
So how do we know if the save worked and if our data is in the format we expect? You can code the data retrieval segment and see what you get or you can jump out into your file system and find the file. On my laptop running Vista (where I am writing this post and running the code) I found the file here:
C:\Users\scottfm\AppData\LocalLow\Microsoft\Silverlight\is\yfs04132.i4g\snux53hm.2bd\1\s\b5nmtb2zfzmydh0dpcsleimmfplr2ioja0i2yvxgpfugozpthhaaadfa\f\UserInfo.xml
Opening it I can see it's in the right format:
Good. Now, let's move on to retrieving data from isolated storage.
Loading Data from Isolated Storage
We'll try to load any previously entered data in the Page class's constructor via the "LoadUserInfo()" method:
1: public Page ()
2: {
3: InitializeComponent ();
4:
5: LoadUserInfo();
6: }
LoadUserInfo's code to then load our file from isolated storage isn't that much different from saving a file except we need to parse out a bit more info to get at our data:
1: private void LoadUserInfo()
2: {
3: using (var isoStore = IsolatedStorageFile.GetUserStoreForApplication ())
4: {
5: if (!isoStore.FileExists ("UserInfo.xml"))
6: {
7: return;
8: }
9:
10: using (var isoStream = new IsolatedStorageFileStream ("UserInfo.xml", FileMode.Open, isoStore))
11: {
12: var xmlEle = XElement.Load (isoStream);
13:
14: foreach (var n in xmlEle.Elements())
15: {
16: string strUI = n.Value;
17:
18: switch (n.Name.LocalName)
19: {
20: case "Name":
21:
22: tbxName.Text = strUI;
23: break;
24:
25: case "WebSite":
26:
27: tbxWebSite.Text = strUI;
28: break;
29:
30: case "Email":
31:
32: tbxEmail.Text = strUI;
33: break;
34:
35: default:
36:
37: break;
38: }
39: }
40: }
41: }
42:
43: return;
44: }
We get access to isolated storage on Line 3, then make sure the file exists before trying to get anything from it. On Line 10 we open the "UserInfo.xml" file and then, using LINQ-to-XML's XElement class, extract the data. If all goes as planned, our form should now contain the data our user entered previously.
Conclusion
Making use of isolated storage is a great way to enhance your users' experience by storing user and environment specific data. Because it's file-based, you can take advantage of file streams, XML, and LINQ-to-XML to make the saving and retrieval of data very simple.
Download: IsolatedStorage.zip
Further Reading
Isolated Storage
Performing Isolated Storage Tasks
IsolatedStorage in Siverlight 2 Beta 1
Isolated Storage in Silverlight 2 Beta 2
How to: Save to and Load from Isolated Storage with LINQ to XML