Where to store your application data?

Actually I don’t intend to answer the question “Where to store your application data?” because this will depend on your requirements, but what this post will look at is, some of the options available and hopefully help shed light on what best suits your application.

Application data can be separated into two types, user specific data and application specific data (or if you prefer “All User” data).

Obviously multiple user’s might have access to a single machine but an application may be available to all users of a machine, hence we need a way to store settings specific to each user on the machine, for example user preferences. However we also may have application specific data, maybe the application stores a list of URL’s specific, in essence global settings.

Let’s look at some of our options for storing data…

Within your application’s folder

Obviously we could simply store configuration data etc. along with the application, one way to locate this folder is, as follows

var folder = Path.GetDirectoryName(
   Assembly.GetExecutingAssembly().Location) +
   Path.DirectorySeparatorChar + 
   SettingsFileName;

Here we might store a file for application specific data then create another file using the username (here we can use the Environment.UserName) of the user logged into the machine for each user.

This is a simple solution and in some cases more than adequate, plus it has the benefit that if we delete the application (i.e. it wasn’t installed via an installer) then we delete any configuration files.

Program Data

The ProgramData folder is on the system drive and is hidden by default (see C:\ProgramData). As can be inferred from the name, it’s generally used for settings specific to the application itself, i.e. not based upon specific users on a machine.

We can access it using the following code

var folder = Path.Combine(
   Environment.GetFolderPath(
      Environment.SpecialFolder.CommonApplicationData),
      "YourAppName");

Interestingly you can access the ProgramData using C:\Users\AllUsers in File Explorer, although File Explorer will state that you are in C:\Users\AllUsers it’s the same folder as C:\ProgramData.

Program Data can also be located using the environment variable %programdata%.

User Data

So we’ve seen that we can use the Environment.UserName to combine with our file name to create user files, but Windows already has the capability locations for user data. Plus, depending how your OS is set up, this data may be used across any machine a user logs into (known as Roaming).

The default location for the following “User Data” folders is under the location C:\Users\<username>\AppData

Local

The Local folder can be located using the special folder LocalApplicationData, for example

var folder = Path.Combine(
   Environment.GetFolderPath(
      Environment.SpecialFolder.LocalApplicationData),
      "YourAppName");

and is also available via the environment variable %localappdata%.

This location contains data that cannot be stored in the Roaming folder, for example data that’s specific to the machine the user is logged into or that is too large to store in a synchronized roaming folder (i.e. where Roaming folders are synchronized with a server).

Roaming

As hinted at in the section on the Local folder. The Roaming folder can be synchronized with a server, i.e. this is a profile which is accessible from other machines that a user logs into on the same domain. Hence anything stored here will “follow” the user around and so is very useful for preferences, favourites etc. However the space available may be limited depending upon quota settings or other space limitations.

To access this folder we simply use the ApplicationData special folder or environment variable %appdata%, for example

var folder = Path.Combine(
   Environment.GetFolderPath(
      Environment.SpecialFolder.ApplicationData),
      "YourAppName");

LocalLow

The LocalLow folder is basically a restricted version of the Local folder. The data is not synchronized with a server and hence does not move from the machine its created on and it has a lower level of access.

When I say “restricted” or “lower level access” basically this means the application being run, itself has security constraints placed upon it.

The LocalLow folder does not have an entry within the SpecialFolder enumeration, so access the folder you need to use the following (copied from Thomans Levesque’s answer on StackOverflow – https://stackoverflow.com/questions/4494290/detect-the-location-of-appdata-locallow)

[DllImport("shell32.dll")]
static extern int SHGetKnownFolderPath(
   [MarshalAs(UnmanagedType.LPStruct)] Guid rfid, 
   uint dwFlags, 
   IntPtr hToken, 
   out IntPtr pszPath);

public static string GetFolderLocalLow()
{
   var pszPath = IntPtr.Zero;
   try
   {
      var hr = SHGetKnownFolderPath(folderGuid, 0, IntPtr.Zero, out pszPath);
      if (hr < 0)
      {
         throw Marshal.GetExceptionForHR(hr);
      }
      return Marshal.PtrToStringAuto(pszPath);
   }
   finally
   {
      if (pszPath != IntPtr.Zero)
      {
         Marshal.FreeCoTaskMem(pszPath);
      }
   }
}

Accessing location via the environment variables

In a few places I’ve shown the environment variable for each of the locations mentioned. We can also use these variables to locate the folders, for example

var location = 
   Environment.ExpandEnvironmentVariables("%AppData%")

This will result in returning the Roaming folder location, but what’s nice is this static method will work with environment variables combined with file locations (as you’d probably expect), so for example

var location = 
   Environment.ExpandEnvironmentVariables("%AppData%\MyApp")

This will return a path along the lines C:\Users\<username>\AppData\Roaming\MyApp