WindowsAppSDK icon indicating copy to clipboard operation
WindowsAppSDK copied to clipboard

LocalSettings throws an UnauthorizedAccessException after AppInstance.Restart

Open sjb-sjb opened this issue 2 years ago • 5 comments

Describe the bug

LocalSettings throws an UnauthorizedAccessException after AppInstance.Restart. How can I fix this?

Expected: should be able to access LocalSettings after a restart.

Steps to reproduce the bug

Using Windows 10 and Windows App SDK, create a WinUI 3 desktop application using the template.

Change MainWindow.xaml to contain this:

<StackPanel Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Center">
    <TextBlock x:Name="TimeTextBlock">(unkown)</TextBlock>
    <Button x:Name="SetButton" Click="Set_Click">Set time</Button>
    <Button x:Name="GetButton" Click="Get_Click">Get time</Button>
    <Button x:Name="RestartButton" Click="Restart_Click">Restart</Button>
    <TextBlock x:Name="StatusTextBlock">Startup</TextBlock>
</StackPanel>

Change MainWindow.xaml.cs to contain this:

    public MainWindow()
    {
        this.InitializeComponent();
    }

    private Windows.Storage.ApplicationDataContainer LocalSettings => this._localSettings ??= Windows.Storage.ApplicationData.Current.LocalSettings;
    private Windows.Storage.ApplicationDataContainer? _localSettings;

    private void Set_Click(object sender, RoutedEventArgs args)
    {
        try {
            DateTimeOffset now = DateTimeOffset.Now;
            this.LocalSettings.Values["Time"] = now;
            this.StatusTextBlock.Text = "Set value " + now.ToString();
        } catch (Exception e) {
            this.StatusTextBlock.Text = $"Exception when setting value, type '{e.GetType().Name}' message '{e.Message}'.";
        }
    }

    private void Get_Click(object sender, RoutedEventArgs args)
    {
        try {
            DateTimeOffset? time;
            if (this.LocalSettings.Values.TryGetValue("Time", out object? value)) {
                time = (DateTimeOffset)value;
            } else {
                time = null;
            }
            this.TimeTextBlock.Text = time?.ToString() ?? "(null)";
            this.StatusTextBlock.Text = "Got value shown above from LocalSettings";
        } catch (Exception e) {
            this.StatusTextBlock.Text = $"Exception when getting value, type '{e.GetType().Name}' message '{e.Message}'.";
        }
    }

    private void Restart_Click(object sender, RoutedEventArgs e)
    {
        AppRestartFailureReason failure = Microsoft.Windows.AppLifecycle.AppInstance.Restart("");
        this.StatusTextBlock.Text = $"Restart failed, '{failure.ToString()}'";
    }

Run the app. Click on the Get and Set buttons, observe it works. Then click on Restart. After the application restart, click on Get or Set and receive an UnauthorizedAccessException.

Expected behavior

Should be able to access LocalSettings after a restart.

Screenshots

No response

NuGet package version

None

Packaging type

Packaged (MSIX)

Windows version

Windows 10 version 22H2 (19045, 2022 Update)

IDE

Visual Studio 2022

Additional context

No response

sjb-sjb avatar Nov 14 '23 04:11 sjb-sjb

I don't see this in a C++ Windows API application running on Windows 11 22H2. Just to ask, since you don't mention it, but did you set the package to partial trust/app container? If AppInstance.Restart detects that the application is packaged and is running in an app container, then it tries to pass the restart request off to CoreApplication.RequestRestartAsync, but this is not a great thing to do. You can see it in the source code in this repo. Currently, desktop applications running in an app container can't use CoreApplication. If your application isn't partial trust, are you able to test it on Windows 11? This could be a Windows 10 issue.

DarranRowe avatar Nov 14 '23 16:11 DarranRowe

Hi @DarranRowe I am using C# and the packaged desktop (WinUI 3) app template. Not sure where the partial trust setting is but if you tell me I will take a look.

sjb-sjb avatar Nov 16 '23 03:11 sjb-sjb

It is very unlikely that you have it set then. The default isn't partial trust, and it is a setting that you have to go out of your way to enable. On the off chance that you enabled it though. If you have a separate packaging project, then you have to select the project name in solution exporer and then select it in properties.

Screenshot 2023-11-16 192224

If you are using the single project layout, then it is even less likely that you could stumble onto this. You would have to manually edit the Package.appxmanifest file and type out either windows.partialTrustApplication and/or appContainer.

DarranRowe avatar Nov 16 '23 19:11 DarranRowe

Yes it’s the single project layout and I did not type the phrase you mention.

sjb-sjb avatar Nov 17 '23 05:11 sjb-sjb