Using SQLite with Windows RT Part 2

Configuration in WinRT apps or where’s the app.config

Coming from a long experience with C# I got used to doing certain things in a way that Microsoft wanted us to do this. For example, configuration in an application was done using app.config files via an API in the System.Configuration namespace that was easy to use for simple things and was extensible enough for complex cases. WinRT does not offer this API, so developers are left to their own devices.

Being used to someone telling me how to do something suddenly left me with a blank sheet of paper to solve this. Should I

  • Read / write my own XML files?
  • Should I use JSON instead of XML?
  • What about basic CSV text files in my own format
  • Should config be readable and writable?

Facing a large number of possible solutions can stop me dead in my tracks (yes I need to check on that with my psychiatrist), but I think I figured a proper way forward thanks to SQLite. Instead of creating a structured XML or JSON file, why not save your configuration in a database?
Pluses:

  • It’s already structured and flexible.
  • It’s represented by a single file.
  • Easily accessed using SQlite API that’s portable enough to be on all platforms

Minuses:

  • Requires a tool to read it outside your app – can’t just open a file and read/modify it

Using SQLite for Configuration in WinRT

WinRT app allows you to package any file along with your binaries by using a Build Action of ‘Content’ – a property you’ll find on a file. For example, if you created a folder in your C# or C++ project (not a filter, a folder!) and put a file into it and mark it with Build Action of ‘Content’, the file will appear under the same folder once it gets deployed onto the device. The example below shows how to make a file called “feed_data.sqlite” available to your app under the “Settings” folder. You can access the file using this path:

C++:

Package::Current->InstalledLocation->Path + "\\Settings\\feed_data.sqlite";

C#:

Package.Current.InstalledLocation.Path + "\\Settings\\feed_data.sqlite";

File as content

There’s one small caveat, however. Anything you package in your deployment is Read-Only. While it limits ability to store any user-generated config, this immutability gives you a piece of mind and confidence that this file cannot change. If for some reason you cannot read it, for example, it’s not because some writer process failed to properly close the file, but because the installation got corrupted. You can ask user to reinstall the app. Anything you put in the file during deployment is guaranteed to be there every time users run your app. This is the default configuration and as far as you are concerned, it’s written in stone.

So what do you do when you need to write something back into configuration? You’ll need to create another sqlite database to manage user-generated configuration and you’ll need to have logic in your app to figure out how to handle the differences between the default configuration and the one written in the user’s area. To get to the user-writable area you’ll need to use the classes in the Windows.Storage namespace. For a simple case, you can use the ApplicationDataContainer.LocalSettings class to reference storage on local device. Look at the ApplicationDataContainer class for other uses.

Here’s how I use sqlite with WinRT to open a database:

Database(Platform::String^ path, bool writablePath) 
{
	if (writablePath)
	{
		_path = ApplicationData::Current->LocalFolder->Path + "\\" + path;
	}
	else
	{
		_path = Package::Current->InstalledLocation->Path + "\\" + path;
	}
	OutputDebugString(_path->Data());
	int rc = sqlite3_open16(_path->Data(), &db);
	Ready = rc == SQLITE_OK;
}

So depending on the value of the writablePath the API either opens the default configuration or the user-writable one.

The first time you run the app, don’t expect the writable configuration to be thre. The sqlite3_open16 function used to open a database will create one if it does not exist, but it will not create any structure you logic requires in it. So you may want to create a function in your app to generate necessary tables if you find that any of them are missing. In my app, I look for a single table and if it does not exist, I assume that the database was created from scratch and attempt to drop and recreate all tables I would need to store user configuration.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s