Persisting User Settings in Silverlight

by Brian Hitney 13. April 2009 10:33

One topic that comes up frequently in dev circles is persisting data in Silverlight applications.  There are a number of ways to do this, and the right solution depends on the data that is being stored.  In ASP.NET applications, user settings are typically stored in a database and often abstracted through a mechanism like the ASP.NET Profile provider in conjunction with the ASP.NET Membership provider.  The make the end user experience a bit better, log in state (or simply the username) is persisted in a cookie. 

In Silverlight, this is still a viable approach (although the data is typically exposed via webservices, depending on the application).

Another approach, however, is to use isolated storage.  Isolated storage can be an effective tool for caching data (with a number of caveats).  In the example below, I’ve created a very simple class that contains the application settings I’d like to persist.   The key methods are Load() and Save().   Out of the box, this will work and you can simply add/remove properties as you’d like. 

   1: public class ApplicationSettings
   2:     {
   3:         [DefaultValue(6)]
   4:         public int MinZoom { get; set; }
   5:  
   6:         [DefaultValue(13)]
   7:         public int MaxZoom { get; set; }
   8:  
   9:         [DefaultValue(8)]
  10:         public int PlotDelay { get; set; }
  11:  
  12:         [DefaultValue(false)]
  13:         public bool RememberSettings { get; set; }
  14:  
  15:         public ApplicationSettings() { }
  16:  
  17:         public static WorldmapsSettings Load()
  18:         {
  19:             ApplicationSettings settings = new ApplicationSettings();
  20:  
  21:             using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())
  22:             {
  23:                 if (!store.FileExists(@"ApplicationSettings.xml"))
  24:                 {
  25:                     return settings;
  26:                 }
  27:  
  28:                 using (var isoStream = store.OpenFile(@"ApplicationSettings.xml",
  29:                     FileMode.Open))
  30:                 {
  31:                     XmlSerializer s = new XmlSerializer(typeof(ApplicationSettings));
  32:                     TextReader r = new StreamReader(isoStream);
  33:                     settings = (ApplicationSettings)s.Deserialize(r);
  34:                     r.Close();
  35:  
  36:                     if (settings != null && settings.RememberSettings)
  37:                     {
  38:                         return settings;
  39:                     }
  40:                     else
  41:                     {
  42:                         return new ApplicationSettings();
  43:                     }
  44:                 }
  45:             }
  46:         }
  47:  
  48:         public void Save()
  49:         { 
  50:             using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())
  51:             {
  52:                 using (IsolatedStorageFileStream isoStream = store.OpenFile(@"ApplicationSettings.xml",
  53:                     FileMode.Create))
  54:                 {
  55:                     XmlSerializer s = new XmlSerializer(typeof(ApplicationSettings));
  56:                     TextWriter writer = new StreamWriter(isoStream);
  57:                     s.Serialize(writer, this);
  58:                     writer.Close();              
  59:                 }
  60:             }
  61:         }
  62:     }

[EDIT]

Silverlight guru Tim Heuer pointed out I’m doing a lot of extra work I don’t need to.   The ApplicationSettings of the IsolatedStorageSettings allows us to stuff objects in it pretty cleanly – so the above could be implemented like so:

   1: public static WorldmapsSettings Load()
   2: {
   3:     
   4:     WorldmapsSettings settings = null;
   5:     
   6:     if (IsolatedStorageSettings.ApplicationSettings.Contains("foo"))
   7:     {
   8:         settings = IsolatedStorageSettings.ApplicationSettings["foo"] as WorldmapsSettings;
   9:     }
  10:     
  11:     if (settings == null)
  12:     {
  13:         settings = new WorldmapsSettings();
  14:     }
  15:  
  16:     return settings;  
  17: }
  18:  
  19: public void Save()
  20: {
  21:     IsolatedStorageSettings.ApplicationSettings["foo"] = this;
  22: }

I can’t think of a good reason not to do it this way, unless some more complex serialization is called for, but even then I can’t come up with a good scenario for that. 

[/EDIT]

 

Now for the caveat.  Isolated storage isn’t secure unless you take some measures to secure it manually.  While you could encrypt the contents, I’d probably recommend not storing data on the client if you’re saving sensitive data.  In the above example, I’m serializing the data using the XML serializer, so the data is obviously in plain text and stored locally:

image

… and it contains the expected object:

   1: <ApplicationSettings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
   2:  xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   3:  <MinZoom>2</MinZoom> 
   4:  <MaxZoom>16</MaxZoom> 
   5:  <PlotDelaySeconds>14</PlotDelaySeconds> 
   6:  <RememberSettings>false</RememberSettings> 
   7: </ApplicationSettings>

Isolated storage offers a lot of potential, but it’s also important to remember the security implications in both exposing the data as well as potential injection points.

Tags: ,

Development | Technology

Comments

4/13/2009 9:31:07 AM #

timheuer

Curious your thoughts on the benefit of this approach versus the built-in methods for IsolatedStorage like: IsolatedStorageSettings.ApplicationSettings["foo"] = "somevalue";

timheuer United States

4/13/2009 9:57:46 AM #

bhitney

Hey Tim -- wow, you know I didn't try that but I just gave it a whirl.  To be honest I don't know why I didn't consider it -- perhaps legacy "DIY" assuming I couldn't stuff an object reference in there.  

I updated the post above with the built in ApplicationSettings implementation.  I can't think a solid reason to not use ApplicationSettings except to possibly control the serialization process with more complex types, but that's clearly not needed here... what do you think?

bhitney United States

4/14/2009 12:55:42 PM #

timheuer

I think for simple stuff like you demonstrate, using the built-in mechanism seems to make sense.  But you are right if you wanted to save a "Order" object, it might make sense to serialize it and save it.

timheuer United States

12/1/2011 4:25:09 PM #

pingback

Pingback from timusenn.allergiesaid.com

Silverlight settings | Timusenn

timusenn.allergiesaid.com

Comments are closed

your host...

Brian Hitney
Developer Evangelist
Microsoft Corp.

About Me

My Worldmap