边缘扩展:当 DesktopBridge 应用程序尝试打开 WebSocket 时,BackgroundTaskInstance 因 SystemPolicy 原因而取消
Edge extension: BackgroundTaskInstance cancels with SystemPolicy reason when DesktopBridge app tries to open WebSocket
我创建了一个 Edge 浏览器扩展,它通过桌面桥技术使用本地消息传递到本地应用程序 运行。我使用 SecureInput 作为示例,其中包含 Edge 扩展、UWP 主机和 Win32 桌面桥应用程序。
我需要 Win32 Desktop Bridge 应用程序使用 HTTP 和 WebSocket 连接到 Web 服务,所以我在包清单中添加了 internetClientServer
和 privateNetworkClientServer
功能,除了已经存在的 runFullTrust
一个.
Win32 Desktop Bridge 应用程序激活得很好,它能够使用 HTTP 连接到 Web 服务器。但是,一旦它尝试打开 WebSocket 连接,UWP 主机上的 BackgroundTaskInstance
就会收到以 BackgroundTaskCancellationReason.SystemPolicy
作为原因的取消请求,并且 Desktop Bridge 应用程序会关闭。遗憾的是,BackgroundTaskCancellationReason.SystemPolicy
的文档并未对取消请求的真实原因进行过多解释。
我尝试使用两个 WebSocket 类:System.Net.WebSockets.ClientWebSocket
和 Windows.Networking.Sockets.MessageWebSocket
,结果相同。没有花哨的代码,只是普通的
var socket = new MessageWebSocket();
...
await socket.ConnectAsync(new Uri("wss://127.0.0.1:9001/myservice"));
相同的 WebSocket 服务端点可从其他 WS 客户端获得,所以我想这里没有 server/firewall/antivirus 问题。
我也玩过CheckNetIsolation
工具,为Edge浏览器和包添加了回环豁免,没有效果。 HTTP 在没有环回豁免的情况下工作正常。
任务取消的真正原因可能是什么,可能的预防方法是什么?
好的,我解决了这个问题。感谢 this comment by Tom Shane 我偶然发现,我意识到 BackgroundTaskCancellationReason.SystemPolicy
告诉系统关闭后台任务以释放一些系统资源,而在我的情况下它发生是因为我没有获得在我的异步事件处理程序中延迟。当事件处理程序在没有延迟的情况下产生时,系统决定它可以关闭任务。以下是代码的摘要版本:
static class Program
{
static AppServiceConnection connection = null;
[STAThread]
static void Main(string[] args)
{
Thread appServiceThread = new Thread(new ThreadStart(ThreadProc));
appServiceThread.Start();
Application.Run();
}
static async void ThreadProc()
{
try {
connection = new AppServiceConnection();
connection.AppServiceName = "...";
connection.PackageFamilyName = Windows.ApplicationModel.Package.Current.Id.FamilyName;
connection.RequestReceived += OnRequestReceived;
connection.ServiceClosed += OnServiceClosed;
var status = await connection.OpenAsync();
....
}
catch (Exception e) { ... }
}
private static async void OnRequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args)
{
var defer = args.GetDeferral(); // <== that was missing, rookie mistake!
try {
var msg = ParseMessage(args.Request.Message);
if (msg.type.Equals("ws")) {
// this method was truly async
// and every time it yielded the issue was revealed
await HandleWsMessage(request, msg);
}
else if (msg.type.Equals("http")) {
// but this method was actually synchronous despite being marked as "async"
// and it never yielded, masking the issue for HTTP client
await HandleHttpMessage(request, msg);
}
}
catch (Exception e) { ... }
finally {
defer.Complete();
}
}
}
我创建了一个 Edge 浏览器扩展,它通过桌面桥技术使用本地消息传递到本地应用程序 运行。我使用 SecureInput 作为示例,其中包含 Edge 扩展、UWP 主机和 Win32 桌面桥应用程序。
我需要 Win32 Desktop Bridge 应用程序使用 HTTP 和 WebSocket 连接到 Web 服务,所以我在包清单中添加了 internetClientServer
和 privateNetworkClientServer
功能,除了已经存在的 runFullTrust
一个.
Win32 Desktop Bridge 应用程序激活得很好,它能够使用 HTTP 连接到 Web 服务器。但是,一旦它尝试打开 WebSocket 连接,UWP 主机上的 BackgroundTaskInstance
就会收到以 BackgroundTaskCancellationReason.SystemPolicy
作为原因的取消请求,并且 Desktop Bridge 应用程序会关闭。遗憾的是,BackgroundTaskCancellationReason.SystemPolicy
的文档并未对取消请求的真实原因进行过多解释。
我尝试使用两个 WebSocket 类:System.Net.WebSockets.ClientWebSocket
和 Windows.Networking.Sockets.MessageWebSocket
,结果相同。没有花哨的代码,只是普通的
var socket = new MessageWebSocket();
...
await socket.ConnectAsync(new Uri("wss://127.0.0.1:9001/myservice"));
相同的 WebSocket 服务端点可从其他 WS 客户端获得,所以我想这里没有 server/firewall/antivirus 问题。
我也玩过CheckNetIsolation
工具,为Edge浏览器和包添加了回环豁免,没有效果。 HTTP 在没有环回豁免的情况下工作正常。
任务取消的真正原因可能是什么,可能的预防方法是什么?
好的,我解决了这个问题。感谢 this comment by Tom Shane 我偶然发现,我意识到 BackgroundTaskCancellationReason.SystemPolicy
告诉系统关闭后台任务以释放一些系统资源,而在我的情况下它发生是因为我没有获得在我的异步事件处理程序中延迟。当事件处理程序在没有延迟的情况下产生时,系统决定它可以关闭任务。以下是代码的摘要版本:
static class Program
{
static AppServiceConnection connection = null;
[STAThread]
static void Main(string[] args)
{
Thread appServiceThread = new Thread(new ThreadStart(ThreadProc));
appServiceThread.Start();
Application.Run();
}
static async void ThreadProc()
{
try {
connection = new AppServiceConnection();
connection.AppServiceName = "...";
connection.PackageFamilyName = Windows.ApplicationModel.Package.Current.Id.FamilyName;
connection.RequestReceived += OnRequestReceived;
connection.ServiceClosed += OnServiceClosed;
var status = await connection.OpenAsync();
....
}
catch (Exception e) { ... }
}
private static async void OnRequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args)
{
var defer = args.GetDeferral(); // <== that was missing, rookie mistake!
try {
var msg = ParseMessage(args.Request.Message);
if (msg.type.Equals("ws")) {
// this method was truly async
// and every time it yielded the issue was revealed
await HandleWsMessage(request, msg);
}
else if (msg.type.Equals("http")) {
// but this method was actually synchronous despite being marked as "async"
// and it never yielded, masking the issue for HTTP client
await HandleHttpMessage(request, msg);
}
}
catch (Exception e) { ... }
finally {
defer.Complete();
}
}
}