.NET has APIs for locating special folders that can be used for application and user configuration and data storage. They provide a convenient, portable way to make cross-platform applications find the appropriate folders on different operating systems. We'll look at how Environment.GetFolderPath
, Path.GetTempPath
, and Path.GetTempFileName
behave on Linux.
Environment.GetFolderPath
The System.Environment
class has two GetFolderPath
overloads:
public static string GetFolderPath (SpecialFolder folder); public static string GetFolderPath (SpecialFolder folder, SpecialFolderOption option);
SpecialFolder
is an enum
with values like ApplicationData
, MyDocuments
, and ProgramFiles
. The SpecialFolderOption
enum
has three values: None
, Create
, and DoNotVerify
. These control the return value when the folder does not exist. Specifying None
causes an empty string to be returned. Specifying Create
causes the folder to be created. And DoNotVerify
causes the path to be returned even when the folder does not exist.
Note that SpecialFolder
and SpecialFolderOption
are nested in the Environment
class, and to use them directly you should add a using static System.Environment;
statement to your code.
To make this API work cross-platform, .NET Core needs to map the SpecialFolder
values to some locations. For Linux, this mapping is based on file-hierarcy and basedir-spec.
SpecialFolder | Environment Variable | Config File | Linux Default |
---|---|---|---|
CommonApplicationData | /usr/share | ||
CommonTemplates | /usr/share/templates | ||
MyDocuments (home) | HOME | passwd | / |
UserProfile | home | ||
ApplicationData | XDG_CONFIG_HOME | home/.config | |
LocalApplicationData | XDG_DATA_HOME | home/.local/share | |
Fonts | home/.fonts | ||
Desktop, DesktopDirectory | XDG_DESKTOP_DIR | user-dirs.dirs | home/Desktop |
Templates | XDG_TEMPLATES_DIR | user-dirs.dirs | home/Templates |
MyVideos | XDG_VIDEOS_DIR | user-dirs.dirs | home/Videos |
MyMusic | XDG_MUSIC_DIR | user-dirs.dirs | home/Music |
MyPictures | XDG_PICTURES_DIR | user-dirs.dirs | home/Pictures |
The table lists all the mapped values in .NET Core 2.1. Other values are not mapped and return an empty string. The returned value is determined from left to right: first checking the environment variable, then falling back to the config file, and finally falling back to a default.
Cross-platform applications should be limited to using the mapped values, or they should be able to fall back to another location when GetFolderPath
returns an empty string.
The user home folder is read from the HOME
environment variable. When that is unset, the home directory is read from the system user database. It’s safe to assume that for known users, .NET Core will be able to determine the home directory. A number of other locations are based on the user home folder. Some can be overridden using environment variables and some others by using a file at ApplicationData/users-dirs.dirs
.
On Windows, most of the special folders will exist by default. This may not be the case on Linux. It is the application's responsibility to create the folder when it doesn't exist. This may require some changes to your code to use the overload with a SpecialFolderOption
.
For example, the following code ensures the LocalApplicationData
folder will be created if it doesn’t exist.
// Use DoNotVerify in case LocalApplicationData doesn’t exist. string appData = Path.Combine(Environment.GetFolderPath(SpecialFolder.LocalApplicationData, SpecialFolderOption.DoNotVerify), "myapp"); // Ensure the directory and all its parents exist. Directory.CreateDirectory(appData);
Path.GetTempPath and Temp.GetTempFileName
The System.IO.Path
class has a method that returns the path of the current user's temporary folder:
public static string GetTempPath ();
Windows applications may assume the path returned here is user-specific. This is because the implementation picks up the USERPROFILE
environment variable. When the variable is unset, the API returns the Windows temp folder.
On Linux, the implementation returns /tmp
. This folder is shared with other users. As a consequence, applications should use unique names to avoid conflicts with other applications. Furthermore, because the location is shared, other users will be able to read the files created here, so you should not store sensitive data in this folder. The first user to create a file or directory will own it. This can cause your application to fail when trying to create a file or directory that is already owned by another user.
The Temp.GetTempFileName
method solves these issues for creating files. It creates a unique file under GetTempPath
that is only readable and writable by the current user.
On Windows, the value returned by GetTempPath
can be controlled using the TMP
/TEMP
environment variables. On Linux, this can be done using TMPDIR
.
On systems with systemd
, like Fedora and Red Hat Enterprise Linux (RHEL), a user-private temporary directory is available and can be located using the XDG_RUNTIME_DIR
environment variable.
Conclusion
In this article, you’ve seen the features and limitations of using Environment.GetFolderPath
, Temp.GetTempPath
and Temp.GetTempFileName
in your cross-platform .NET Core applications.
Here are some additional .NET Core articles that might be helpful:
- Improving .NET Core Kestrel performance using a Linux-specific transport
- Using OpenShift to deploy .NET Core applications
- Running Microsoft SQL Server on Red Hat OpenShift
- Securing .NET Core on OpenShift using HTTPS
- Announcing .NET Core 2.1 for Red Hat Platforms
Last updated: September 3, 2019