microsoft / WindowsAppSDK

The Windows App SDK empowers all Windows desktop apps with modern Windows UI, APIs, and platform features, including back-compat support, shipped via NuGet.
https://docs.microsoft.com/windows/apps/windows-app-sdk/
MIT License
3.8k stars 320 forks source link

Requesting push notification channel on a background task throws COMException #3764

Open Diegorro98 opened 1 year ago

Diegorro98 commented 1 year ago

Describe the bug

I'm trying to create a flow where a background task updates the push notification channel when the app is updated. The background task runs fine, but when the task calls to CreateChannelAsync, it produces the following exception:

'System.Runtime.InteropServices.COMException' at WinRT.Runtime.dll
WinRT Info: Unspecified Error

Steps to reproduce the bug

In a project with a background task, in the background task project:

  1. Install WindowsAppSDK NuGet
  2. Set the content of the Run method to the following:
    public async void Run(IBackgroundTaskInstance taskInstance)
    {
        var deferral = taskInstance.GetDeferral();
        try
        {
            if (PushNotificationManager.IsSupported())
            {
                var remote_id = "7edfab6c-25ae-4678-b406-d1848f97919a";  // Replace this with your own Azure ObjectId
                var channelOperation = PushNotificationManager.Default.CreateChannelAsync(new(remote_id));
                channelOperation.Progress = (sender, args) =>
                {
                    if (args.status == PushNotificationChannelStatus.InProgress)
                    {
                        Debug.WriteLine($"Channel request is in progress.");
                    }
                    else if (args.status == PushNotificationChannelStatus.InProgressRetry)
                    {
                        Debug.WriteLine($"The channel request is in back-off retry mode because of a retryable error");
                    }
                };
                var requestTask = channelOperation.AsTask();
                var completedTask = await Task.WhenAny(requestTask, Task.Delay(300000));
                if (completedTask != requestTask)
                {
                    Debug.WriteLine($"Channel request timeout.");
                    return null;
                }
                var result = channelOperation.GetResults();
                if (result.Status == PushNotificationChannelStatus.CompletedSuccess)
                {
                    return result.Channel;
                }
                else if (result.Status == PushNotificationChannelStatus.CompletedFailure)
                {
                    Debug.WriteLine($"Critical non-retryable error with channel request!");
                    return null;
                }
                else
                {
                    Debug.WriteLine($"Some failure occurred while requesting push channel.");
                    return null;
                }
            }
        }
        catch (Exception)
        {
        }
        finally
        {
            deferral.Complete(); 
        }
    }

Expected behavior

It should get the channel URI when the background task is executed so that when the app is updated, because the channel is expired, the channel can be updated automatically. It should get it just like it does with the same instructions at the main app project, which works fine and creates a channel that allows me to send push notifications by following the instructions from this resource: Quickstart: Push notifications in the Windows App SDK

NuGet package version

Windows App SDK 1.3.2: 1.3.230602002

Packaging type

Packaged (MSIX)

Windows version

Insider Build (10.0.22631)

IDE

Visual Studio 2022

Additional context

I also tried with PushNotificationChannelManager:

await PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAsync();

and

await PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAsync(remote_id);

The first option was able to return an URI, but when trying to send the notification, it returned a 403 HTTP error. The second raised the following exception:

'System.Runtime.InteropServices.COMException' at System.Private.CoreLib.dll
Element not found. (0x80070490)


I got the idea to update the push notification channel when the update task is triggered from this resource: Run background task when your UWP app is updated

Diegorro98 commented 8 months ago

@bpulliam Any updates on this? I need a way to update the channel whenever the app updates (so the update background task is launched). Another idea I had was to use Launcher.LaunchUriAsync to open the app and update the registration, but it raises an InvalidOperationException...

Diegorro98 commented 8 months ago

Btw, inspecting a little bit deeper the stack trace, I realized that the exception is launched when using PushNotificationManager.Default (So Default getter is called). Stacktrace:

at WinRT.ExceptionHelpers.< ThrowExceptionForHR>g_Throw|39_0(Int32 hr)
at WinRT.ExceptionHelpers.ThrowExceptionForHR(Int32hr)
at ABI.Microsoft.Windows.PushNotifications.IPushNotificationManagerStaticsMethods.get_Default(IObjectReference _obj)
at Microsoft.Windows.PushNotifications.PushNotificationManager.get_Default()
at App.BackgroundTasks.BackgroundTask.Run(IBackgroundTaskInstance taskInstance)