GameDex - The Road to Release 1.0.0 - Storing Files

  • Chris Wallace
  • Sat May 25 2013

It's been a few weeks since my two sites went live and now I'm focusing my efforts back in the world of windows store apps. Windows 8 opinions seem to be split right down the middle-ish, but since I got my touchscreen laptop I can see the benefits of the Modern UI.

The store itself also has so much potential, admittedly there's a lot of garbage in the store (as there is with any app store) and the key apps you find on other platforms aren't there. But is that a bad thing? If you're a .net or JavaScript developer wanting to build your first app it's a rare opportunity to have so many choices for a project, frankly, it's an untapped resource.

So my first app GameDex is well underway, and although it's tempting to start playing with UI and Xaml, I've started laying the groundwork first.

Being an inventory application means there has to be a heavy emphasis on not just storage, but accessible storage. If you're keeping track of all your games you may want to have that list somewhere handy on your PC, or maybe across multiple PCs, or maybe you don't care and just want the app to take care of it. These use case scenarios have been my main emphasis over the past fortnight and I've come up with three storage strategies for the app.

  1. LocalStorage - Keep it simple, keep it local. The simplest option (and by far the easiest to get your head round from a dev standpoint), using local storage means keeping my library (a JSON file) and media folders stored as part of local storage. What's happening in the code chunk below is the App is creating a new StorageFolder object (as part of WinRT). Then within that StorageFolder it creates another StorageFolder (Media for storing images etc) and finally creates a StorageFile "gdex.json" which will store the library data. The JSON data is serialized using a great StorageHelper class by Jerry Nixon then written to the JSON file.

public async static Task NewLibraryInApp()
{
StorageFolder rootFolder = await Windows.Storage.ApplicationData.Current.LocalFolder.CreateFolderAsync("GameDex", CreationCollisionOption.ReplaceExisting);
await rootFolder.CreateFolderAsync("Media");
if (await StorageHelper.WriteFileAsync("gdex.json", App.GameDexModel, rootFolder))
{
StorageHelper.SetSetting("GameDexLocation", "Local", StorageHelper.StorageStrategies.Roaming);
return true;
}
else
{
return false;
}
}

Once the folder structure has been written, we finally save some app settings to Roaming Data (settings linked to our Microsoft Account so we acn reuse them later). We set the "GameDexLocation" setting to "Local" so the App knows to check Local storage whenever it loads.

The Advantages? It's a quick way to get the App up and running, no need for authentication or further file permissions. The Disadvantage? It's all in the app. So if you're looking to duplicate your library or move it, or worst case your PC dies, you've lost your GameDex. The only other implementation I could use (which may be introduced down the line) is using Roaming storage.

Roaming Storage works just like Local except the files and folders are synced across Windows 8 devices using your Microsoft account. The perfect situation, however, there are gotchas, Roaming storage has a daily quota (files stored, transaction limit) and if this quota is reached the app stops working, we don't want that. Plus if we're storing images etc in that media folder then Roaming storage is going to fill up fast, so what're the other options...

  1. Documents Storage - old school with some new rules. Still keeping it local but making it a bit more accessible, using some extra WinRT file permissions we can save your library directly within a user's documents folder. There's a few more things happening here but in essence it's just changing the save location. Using a FolderPicker dialog (new to WinRT) we can choose the folder to create our GameDex folder (and then our json file and Media folder). Then once the files are created we need to set the "GameDexLocation" setting to "Documents", and add an extra Roaming setting for the file "Path".

public async static Task NewLibraryInDocuments()
{
FolderPicker installDirectoryPicker = new FolderPicker();
installDirectoryPicker.ViewMode = PickerViewMode.Thumbnail;
installDirectoryPicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;
installDirectoryPicker.FileTypeFilter.Add("*");
installDirectoryPicker.CommitButtonText = "Install Here";
var folderSelection = await installDirectoryPicker.PickSingleFolderAsync();
StorageFolder rootFolder = await folderSelection.CreateFolderAsync("GameDex", CreationCollisionOption.ReplaceExisting);
string path = rootFolder.Path;
await rootFolder.CreateFolderAsync("Media");
if (await StorageHelper.WriteFileAsync("gdex.json", App.GameDexModel, rootFolder))
{
StorageHelper.SetSetting("GameDexLocation", "Documents", StorageHelper.StorageStrategies.Roaming);
StorageHelper.SetSetting("Path", path, StorageHelper.StorageStrategies.Roaming);
return true;
}
else
{
return false;
}
}

The Advantages? It follows a more traditional way of developing for Windows, settings, and files are stored in an accessible location on the hard drive which could be backed up or even used in conjunction with another application or service. The Disadvantages? Storing in documents is partially taboo. The files are more accessible to the user meaning more room for tampering and error. Windows 8 doesn't even allow it without applying additional capabilities (to enable Document storage, check the 'Documents' checkbox under the Package.appxmanifest file).

Although keeping storage within the App is the way of the world, for now, Windows users still like their traditions, and accessible App files are one of them. So giving the option of saving to their documents is a reasonable compromise (heck they could even sync their GameDex library to a USB drive, other PC or even with something like Dropbox). But we're now living in a cloudy world, so maybe storage in the cloud is an option.....

  1. Cloud Storage with Azure and SkyDrive - The final option is the most versatile of the three, it requires a few extra user permissions (and the most complex sync wise) but allows the user to use their GameDex from any Windows 8 device. The storage strategy is to keep all the user's gamedex data in cloud storage. Using the LiveSDK for SkyDrive storage and Azure Mobile Services we can keep all the user's data remote and safe.

Both platforms have their advantages and limitations. Azure mobile services is a new service from Microsoft which allows you to store a user's App data in Azure, the backend is a SQL database but Azure mobile services handles the service layer for you. SkyDrive works similar to that of Document storage however it's all remote so a series of REST calls are used to make file transactions.

So how does it work? Initially, we need to do some authentication to SkyDrive using the user's Microsoft Account, then we need to do the same for Azure Mobile services (technically they're two services so there have to be two authentication calls). Once authenticated we serialize the App model to JSON and store it in Azure. Then finally create the required folders in SkyDrive (GameDex and Media). Once the Library is in Azure and the folders are in SkyDrive we can set our Roaming settings for further use.

public async static Task NewLibraryInSkyDrive()
{
if (await SkyDriveController.InitAuth())
{
await AzureMobileController.Authenticate();
if (await AzureMobileController.AddNewAppModel())
{
//Setup Local Environment to Sync Against
StorageFolder rootFolder = await Windows.Storage.ApplicationData.Current.LocalFolder.CreateFolderAsync("GameDex", CreationCollisionOption.ReplaceExisting);
string path = rootFolder.Path;
await rootFolder.CreateFolderAsync("Media");
if (await SkyDriveController.setupNewSkyDriveEnvironment())
{
StorageHelper.SetSetting("GameDexLocation", "SkyDrive", StorageHelper.StorageStrategies.Roaming);
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
else
{
return false;
}
}

But why use both Azure and SkyDrive? Well, frankly both services complement each other. Azure mobile services are great for storing App data, but storing files (images etc) can be costly and hold too much responsibility (you're holding everyone's files on your cloud service, imagine if they filled it up with garbage?).

So Azure Mobile services isn't exactly a complete solution, particularly if you're just starting out with App development. So this is where SkyDrive comes in. Storing all the media files on the user's SkyDrive means they're still in control of their files and a free to fill it up with whatever they wish, there's less storage cost for Azure and it doesn't touch any of their files. They can even download their SkyDrive files or view them using other Apps.

But SkyDrive has one flaw, it can't store just any file, in fact, Microsoft stress SkyDrive is not to be used to store App data (so XML and JSON etc are out). This is understandable to a point, the SkyDrive service puts heavy emphasis on human-readable files (images, word documents, videos etc), and shoving a load of XML files could annoy the user. Using SkyDrive to store our GameDex media files is fine because it will always consist of user submitted files (such as images and in the future docs and video). Which is why we store the User's library in Azure mobile services, it's App generated data and serves no purpose outside the App so shouldn't reside on SkyDrive. Hence why both services complement each other, Azure for App data, SkyDrive for user files.

So enough tech talks for one post, where am I at with the App? The groundwork is now in place, you can create a new GameDex library locally, in documents and in the cloud. The app will even ask if you want to locate an existing library in case you're a returning GameDex user. The next steps are to add file sync methods, so users opening the App can sync their library and files to their location. Then finally the serious work beings getting game data, presenting it aesthetically with the Modern UI and saving it the library.