2

According to the documentation, calls to System.Environment.GetFolderPath can fail with PlatformNotSupportedException:

try
{
    var appData = System.Environment.SpecialFolder.ApplicationData;
    var folder = System.Environment.GetFolderPath(appData);
    // Read/write files in ApplicationData
}
catch (System.PlatformNotSupportedException ex)
{
    System.Console.WriteLine("Environment paths not supported: " + ex.Message);
    // Does this ever actually happen?
}

Unfortunately, the official documentation doesn't list supported or unsupported platforms.

Searching in the .net core sources reveals references to Windows.Storage calls (e.g. UserDataPaths.GetDefault(), AppDataPaths.GetDefault(), ApplicationData.RoamingFolder property), System.Runtime.InteropServices calls, and Interop.Shell32.KnownFolders calls. None of these are marked as throwing a PlatformNotSupportedException.

Are there any known platforms that can actually trigger this exception? If so, which ones?

Brian
  • 3,850
  • 3
  • 21
  • 37
  • It probably doesn't throw that exception right now as all the currently supported platforms support directory structures. – DavidG Aug 20 '18 at 17:02
  • You might consider opening an issue for this on CoreFX, because the obvious and documented remedy for platforms not supporting any of the special paths is to return the empty string for all arguments, and that's largely the approach taken for most "special" folders on non-Windows platforms. Notably, none of them throw `PlatformNotSupportedException` for just *some* folders, which might actually be helpful (as otherwise, a missing test for an empty string might leave the application looking in the working directory, which might be quite bad in some cases). An exception doesn't appear needed. – Jeroen Mostert Aug 20 '18 at 18:07
  • Interestingly, the full .NET Framework [does have code](https://referencesource.microsoft.com/#mscorlib/system/environment.cs,1479) (possibly vestigial) that throws PNSE. On Windows, it will throw if and only if `SHGetFolderPath` returns `COR_E_PLATFORMNOTSUPPORTED`, which I think requires some kind of shim and does not actually apply to Win32 -- the native shell implementation won't produce that, what with `COR_E` being a .NET HRESULT and all that. – Jeroen Mostert Aug 20 '18 at 18:55
  • @JeroenMostert Nice find! I opened an issue for the documentation on Github; the dotnet team pointed me at the same file. I agree that it looks vestigial; maybe it's a leftover from the early days of .net... – Brian Aug 20 '18 at 19:35
  • It's possible (but too shrouded by history -- I mean, Microsoft deleting old docs) that there were live implementations for .NET Compact, Micro, old Windows Phone etc. where this method actually did throw, instead of just returning an empty folder. It would be hard to verify now without hunting down some old SDKs. In any case, I don't think this is going to be the strategy moving forward, since even proverbial potatoes have some kind of file system these days. (And even on potatoes, deferring exceptions until we actually try to access files seems more reasonable.) – Jeroen Mostert Aug 20 '18 at 19:40
  • There's an open issue on github for this: https://github.com/dotnet/docs/issues/7126 – Brian Aug 29 '18 at 17:18

1 Answers1

1

About System.Environment.SpecialFolder, the official document says:

Special folders are set by default by the system, or explicitly by the user, when installing a version of Windows.

Different System could support different KNOWN folders, or retire folders, change rules of existing folders, and so on. You can extend known folders as well for your project that you are aiming to.

Here is output lists of different Operation Systems:

  1. Environment.GetFolderPath(...CommonApplicationData) is still returning "C:\Documents and Settings\" on Vista
  2. https://jimrich.sk/environment-specialfolder-on-windows-linux-and-os-x/
  3. https://johnkoerner.com/csharp/special-folder-values-on-windows-versus-mac/

by above links, for example, when you call: System.Environment.SpecialFolder.History or System.Environment.SpecialFolder.Cookies or many other folders in Mac/Linux, it will not give you a path.

you can try this method to add simple support:

Environment.SpecialFolder.Cookies.Path();

Here is sample code:

public static class KnownFoldersExtensions
{
    public static string Path(this Environment.SpecialFolder folder)
    {
        var path = Environment.GetFolderPath(folder);
        if (string.IsNullOrEmpty(path))
        {
            throw new PlatformNotSupportedException();
        }
        return path;
    }
}

or

public static class KnownFoldersExtensions
{
    public static string Path(this Environment.SpecialFolder folder)
    {

        var path = Environment.GetFolderPath(folder);
        if (!string.IsNullOrEmpty(path))
        {
            return path;
        }

        switch (folder)
        {
            case Environment.SpecialFolder.Cookies:
                {
                    //detect current OS and give correct folder, here is for example only
                    var defaultRoot = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
                    return System.IO.Path.Combine(defaultRoot, "Cookies");
                }
            //case OTHERS:
            //    {
            //        // TO DO
            //    }
            default:
                {
                    //do something or throw or return null
                    throw new PlatformNotSupportedException(folder.ToString());
                    //return null;
                }
        }

    }
}
Dongdong
  • 2,208
  • 19
  • 28
  • 1
    It will *not* throw an exception. The .NET Core implementations only ever return empty strings for unsupported folders. The links you've provided actually back that up. What you *can* get, if passing an out-of-range value for the enum, is an `ArgumentOutOfRangeException`, but that's not related to the platform you're targeting but which runtime version you're using. – Jeroen Mostert Aug 20 '18 at 19:04
  • The notes about extending known folders on Windows aren't relevant, since you can't get custom or future-version unknown folders using `GetFolderPath` -- it has no support for that. Even if the call manages to end up a failure in `SHGetKnownFolderPath`, though, this will still just be converted to an empty string. – Jeroen Mostert Aug 20 '18 at 19:10
  • 1
    Thanks for posting @Dongdong, but I'm interested in the conditions when `Environment.GetFolderPath` will throw the PlatformNotSupported exception -- not how to throw it myself. While your notes on extending Known Folders are interesting, they're not germane to my question. – Brian Aug 20 '18 at 19:37