Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Microsoft.Storage.ApplicationData #2639

Open
DrusTheAxe opened this issue Jun 17, 2022 · 8 comments
Open

Microsoft.Storage.ApplicationData #2639

DrusTheAxe opened this issue Jun 17, 2022 · 8 comments

Comments

@DrusTheAxe
Copy link
Member

DrusTheAxe commented Jun 17, 2022

Proposal: Microsoft.Storage.ApplicationData

Summary

Provide a modern enhanced version of Windows.Storage.ApplicationData and Windows.Management.Core.ApplicationDataManager

Microsoft-internal task 40050113

Rationale

  • Windows.Storage.ApplicationData.Current only works if you have package identity AND running in AppContainer
  • Windows.Management.Core.ApplicationDataManager.CreateForPackageFamily is equivalent but requires you have package identity AND running MediumIL or higher
  • Unpackaged apps have long been advised to use %LOCALAPPDATA%\publisher\product, %LOCALAPPDATA%\Temp and HKCU\SOFTWARE\publisher\product but ApplicationData doesn't support that
  • Windows.Storage.ApplicationData has several deprecated and obsolete features (e.g. .RoamingFolder)
  • ApplicationData.*Folder only provide access to the filesystem via StorageFolder. There's no way to get their .Path without going thrug a StorageFolder incurring significant performance overhead
  • ApplicationData has async methods which should be available synchronously e.g. ClearAsync() should offer `Clear() as a synchronous variant (or replacement?)

Windows App SDK can and should provide a modern revision of the ApplicationData API, addressing the issues above (one API supporting both packaged and unpackaged apps).

Scope

Capability Priority
APIs equivalent to Windows.Storage.ApplicationData (minus deprecated APIs) Must
APIs available to packaged and unpackaged applications Must
APIs offer filesystem access without requiring use of StorageFolder Must
Synchronous equivalents to Windows.Storage.ApplicationData.*Async() APIs Must
WinRT API Must

Important Notes

Microsoft.Storage.ApplicationData supports packaged and unpackaged apps. The underlying data stores are different but equivalent(ish):

Packaged Unpackaged
ApplicationData.LocalCacheFolder %LOCALAPPDATA%\<publisher>\<product>
ApplicationData.LocalFolder %LOCALAPPDATA%\<publisher>\<product>
ApplicationData.MachineFolder %ProgramData%\<publisher>\<product>
ApplicationData.RoamingFolder %LOCALAPPDATA%\Roaming
ApplicationData.TemporaryFolder %LOCALAPPDATA%\Temp
ApplicationData.LocalSettings HKCU\SOFTWARE\<publisher>\<product>

WinRT API

Here's a sketch of the general shape of the API to express the intent of the ask. The actual API when designed/spec'd/reviewed/approved may differ.

Microsoft.Storage.ApplicationData.idl

namespace Microsoft.Storage.ApplicationData
{
[contract(ApplicationData, 1)]
enum ApplicationDataLocality
{
    // NOTE: Values compatible with Windows.Storage.ApplicationDataLocality
    Local = 0,
    LocalCache = 3,
    SharedLocal = 4,
    Temporary = 2,
}

[contract(ApplicationData, 1)]
runtimeclass ApplicationData
{
    /// Return an ApplicationData object if the current process has package identity
    /// NOTE: This is equivalent to `ApplicationData.ForPackageFamily(Windows.ApplicationModel.Package.Current.Id.FamilyName)`
    static ApplicationData GetDefault();

    /// NOTE: Requires MediumIL (or higher) if the process lacks package identity.
    /// NOTE: Requires MediumIL (or higher) if the process has package identity but different from the packageFamilyName parameer.
    /// NOTE: GetForPackageFamily(Windows.ApplicationModel.Package.Current.Id.FamilyName) is equivalent to GetDefault()
    static ApplicationData GetForPackageFamily(String packageFamilyName);

    /// NOTE: Requires admin privilege if user != current user
    /// NOTE: GetForUser(Window.System.User.GetDefault) is equivalent to GetDefault()
    static ApplicationData GetForUser(Windows.System.User user);

    /// NOTE: Requires admin privilege if user != current user
    /// NOTE: GetForUser(Window.System.User.GetDefault, packageFamilyName) is equivalent to GetForPackageFamily(packageFamilyName)
    static ApplicationData GetForUser(Windows.System.User user, String packageFamilyName);

    StorageFolder LocalCacheFolder;
    StorageFolder LocalFolder;
    StorageFolder TemporaryFolder;
    StorageFolder SharedLocalFolder;    //NOTE: Returns NULL if process lacks package identity

    String LocalCachePath;
    String LocalPath;
    String TemporaryPath;
    String SharedLocalPath; //NOTE: Returns NULL if process lacks package identity

    ApplicationDataContainer LocalSettings;

    void Clear();
    void Clear(ApplicationDataLocality locality);

    AsyncAction ClearAsync();
    AsyncAction ClearAsync(ApplicationDataLocality locality);
}
}

Open Questions

Q: Is there an unpackaged equivalent to GetPublisherCacheFolder()?

@DrusTheAxe
Copy link
Member Author

See #2621 (comment) for the latest discussion that sparked the creation of this issue

@riverar
Copy link
Contributor

riverar commented Jun 17, 2022

Windows.Storage.ApplicationData.Current only works fir you have package identity AND running in AppContainer

Nit: I'd add the word reliably in there (e.g. only works reliably), just to bring attention to how evil this API truly is. Because the API does work most of the time, it misleads devs and puts them on a path to failure.

Otherwise thanks for writing this up and moving the needle. I've been talking about these tricky APIs/scenarios since around 2017!

@DrusTheAxe
Copy link
Member Author

Windows.Storage.ApplicationData.Current only works if you have package identity AND running in AppContainer

Nit: I'd add the word reliably in there (e.g. only works reliably), just to bring attention to how evil this API truly is. Because the API does work most of the time, it misleads devs and puts them on a path to failure.

Can you elaborate on what you find unreliable about ApplicationData.Current?

Is it really unreliable or rather the complexity of having to understand the right contexts it does/not support (i.e. the Rationale's first 3 bullets)?

@riverar
Copy link
Contributor

riverar commented Jun 17, 2022

Can you elaborate on what you find unreliable about ApplicationData.Current?

ApplicationData.Current.LocalSettings usage outside of AppContainer is on a best effort basis I'm told. Was a top crasher for EarTrumpet (runFullTrust app) until I replaced it recently with ApplicationDataManager.CreateForPackageFamily(...).LocalSettings. 😎

@lukeblevins
Copy link

lukeblevins commented Jun 21, 2022

  • ApplicationData.*Folder only provide access to the filesystem via StorageFolder. There's no way to get their .Path without going thrug a StorageFolder incurring significant performance overhead

Can definitely see the importance of getting a filesystem Path without StorageFolder. However, it would be valuable to know whether Microsoft sees the performance overhead as inevitable with StorageFolder/StorageFile. #8 is obviously a separate issue to tackle, but should new APIs really be built around paths if an improved StorageFolder (or something new) is on the backlog?

EDIT: IDL in spec shows that both a StorageFolder and Path will be available for the given locations, so this seems like less of a statement on the future of StorageFolder and more about facilitating interoperability from non Windows.Storage APIs which take a filesystem path.

Gets a 👍🏻 from me

@DrusTheAxe
Copy link
Member Author

EDIT: IDL in spec shows that both a StorageFolder and Path will be available for the given locations, so this seems like less of a statement on the future of StorageFolder and more about facilitating interoperability from non Windows.Storage APIs which take a filesystem path.

Bingo! :-)

@anlocnghg
Copy link

anlocnghg commented Jul 9, 2022

Just to let you know what I did (a manual and not an elegant solution) to walkaround the Windows.Storage.ApplicationData for now:

  1. Use System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) to replace the (path to) local storage folder (Windows.Storage.ApplicationData.Current.LocalFolder).
  2. Use XML for local settings (Windows.Storage.ApplicationData.Current.LocalSettings).

Edited: for my situation only as in discussion #2618

@DrusTheAxe
Copy link
Member Author

Use System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) to replace the (path to) local storage folder (Windows.Storage.ApplicationData.Current.LocalFolder).

BTW that's not equivalent. ApplicationData.LocalFolder is a per-user location in your user profile1,2 but GetExecutingAssembly() is wherever the assembly is located (i.e. where your .exe or .dll lives). That could be in your user profile but could be lots other places, and it's the same answer for the assembly regardless of the user.

Windows.Storage.AppDataPaths.GetDefault().LocalAppData + \publisher\product is the unpackaged equivalent to ApplicationData.Current.LocalFolder -- a per-user location for data for the product/package.

Windows.Storage.AppDataPaths.GetDefault().LocalAppData == SHGetKnownFolderPath(KnownFolderID_LocalAppData...) == %LOCALAPPDATA% == %USERPROFILE%\AppData\Local (but APIs are better than environment variables as the latter can be trivially altered/hacked; they're not reliable or definitive sources of the answer, those APIs are).

1 Maybe. ApplicationData for a package family exists under %USERPROFILE% if the package is installed on %SystemDrive% (i.e. C:) but if you install packages to other drives then their ApplicationData will be created on the same drive e.g. install a packaged app on Q: and ApplicationData.LocalFolder will likewise be located on Q:

2 But that's not absolute. If you then move the package to another drive the package moves but not the data e.g. pkgmgr.MovePackageAsync(foo,...) from Windows.ApplicationModel.Package.InstalledPath=Q:... to M:... but ApplicationData will still be on Q:

DrusTheAxe added a commit that referenced this issue Jan 30, 2024
* Microsoft.Storage.ApplicationData #2639

* Added details about per-machine data store

* Incorporated feedback

* Moar doc-comments

* Removed ClearAllAsync and ClearMachineAsync. Use ClearAsync(locality)

* Removed typo

* Fixed some long-line formatting

* Incorporated API Review feedback
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants