WinRT RoamingSettings and Serialization

Recently, a colleague of mine, Adam Hoffman, posted a great tip on serializing a generic List<t> to a Windows 8 App’s RoamingSettings.   As Adam points out, taking advantage of roaming storage is so easy to do, it’s criminal not to take advantage of it.  There are three basic types of data:  local, roaming, and temporary.  The APIs are all used similarly, and more info on them can be found here.

There are a few things to keep in mind when using roaming data.  One is:  the data might change after the app is running – perhaps the data hadn’t been synchronized from another machine yet, or the app is concurrently being used elsewhere.  You can plug into the DataChanged event handler to be notified when the roaming data for your app changes – and if it does change, decide what you want to do.  You might choose to refresh the settings, or allow the user to decide if they’d like to use these new settings.

The biggest thing to be keep in mind, however, is the RoamingStorageQuota.  By design, roaming storage was intended to be for preferences or small amounts of data.  At present, the quota is set to a paltry 100KB – although that seems unnecessarily small, if you have hundreds of apps taking advantage of this feature, I can see where bandwidth conversation might come into play. 

Accessing the RoamingStorageQuota returns a ulong of the current quota in KB:

  ulong quota = ApplicationData.Current.RoamingStorageQuota;
  

Perhaps at some point the 100KB number will be increased.  If your app exceeds that number, the data will be persisted locally, however will not roam.  This can be a difficult bug to track down, particularly if you’re roaming important data.  Also, when running on a developer machine, the RoamingStorageQuota returns 0 – presumably, because the data can’t roam as it’s not a store-based app (yet).  I’ve asked some people internally to confirm this, but in short, means you’ll have to anticipate the value coming back – I’m assuming that return value is 100. 

Building off of Adam’s example, we could do something like:

 private static string SerializeToString(object obj)
 {
     XmlSerializer serializer = new XmlSerializer(obj.GetType());
     using (StringWriter writer = new StringWriter())
     {
         serializer.Serialize(writer, obj);
         return writer.ToString();
     }
 }
  
 public void Save()
 {
     ApplicationDataContainer settingsRoaming =
         ApplicationData.Current.RoamingSettings;
     this.LastModified = DateTime.Now;
     string serializedData = SerializeToString(this);
  
     if ((ulong)UnicodeEncoding.Unicode.GetByteCount(serializedData) <=
         ApplicationData.Current.RoamingStorageQuota)
     {
         settingsRoaming.Values["appSettings"] = serializedData;
     }
     else
     {
         //handle the situation
     }
 }

 

I realized after writing this (and using this logic myself) that it wouldn’t be a good idea:  a single setting can be at most 8KB, while a composite value can be up to 64KB in size.   A composite setting represents an atomic unit, and can store much more information obviously.  They can be used as follows:

 // Composite setting

Windows.Storage.ApplicationDataCompositeValue composite = 
   new Windows.Storage.ApplicationDataCompositeValue();
composite["intVal"] = 1;
composite["strVal"] = "string";

roamingSettings.Values["exampleCompositeSetting"] = composite;

Now, I’m making an assumption that the data is stored in Unicode, 2 bytes per character.  I could be wrong.  Also, I’m uncertain of the actual size of each element in the settings – a DateTime is typically 8 bytes but I’m uncertain if it gets serialized and consumes only 8 bytes of roaming storage. 

In addition to all this, roaming data also can contain folders and files.  While obviously limited in size, this may be preferred depending on the type of data your app is using. 

The bottom line is:  be cautious if trying to roam user-generated data instead of predictable application settings, and consider serializing them as a JSON object graph to a file, to conserve space (XML-based serialization is verbose).  For other thoughts on this, see another one of my colleague’s posts on the subject:  Windows 8 Games and Roaming Data.