如何解决为什么 .NET 通用主机与 WinUI3 一起使用时不会停止?
我正在使用 .NET 5 编写 WinUI3(Project Reunion 0.5)应用程序,并想使用 .NET 通用主机。我使用带有自定义 IHostedService
的默认主机:
public App() {
_host = Host.CreateDefaultBuilder()
.ConfigureServices((context,services) =>
{
services.AddHostedService<MyHostedService>();
}).Build();
InitializeComponent();
}
托管服务在 StopAsync
中执行一些异步操作。出于演示目的,假设它延迟了 1 秒(此代码仍然会产生问题):
public override async Task StopAsync(CancellationToken cancellationToken)
{
await Task.Delay(1000);
}
我在 OnLaunched
启动主机:
protected override async void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
{
await _host.StartAsync();
m_window = new MainWindow();
m_window.Activate();
}
我让默认的 ConsoleLifetime
实现在进程退出之前停止主机。
我的 Task
实现返回的 IHostedService.StopAsync
已完成,但 IHost.StopAsync
永远不会返回并且进程在输出中挂起此消息:
Microsoft.Hosting.Lifetime: information: Application is shutting down...
Microsoft.Hosting.Lifetime: information: Waiting for the host to be disposed. Ensure all 'IHost' instances are wrapped in 'using' blocks.
如果我单步调试调试器,有时 IHost.StopAsync
方法会超时并抛出异常。这永远不会发生在调试器之外。我曾尝试在 MainWindow
关闭时明确停止和处置主机,但没有任何区别。
我认为 dispatcherQueueSynchronizationContext
可能在主机停止并且任务没有得到服务之前被关闭,但 dispatcherQueue.ShutdownStarting
事件从未被触发。
还有其他想法吗?
解决方法
我从评论中接受了@Dai 的建议,并调查了在单独的线程上运行 WinUI 并在主线程上运行主机。
我创建了一个 IHostedService
来管理 WinUI 应用程序:
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using Microsoft.System;
using Microsoft.UI.Xaml;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace MyApp.Hosting
{
public class WinUIHostedService<TApplication> : IHostedService,IDisposable
where TApplication : Application,new()
{
private readonly IHostApplicationLifetime HostApplicationLifetime;
private readonly IServiceProvider ServiceProvider;
public WinUIHostedService(
IHostApplicationLifetime hostApplicationLifetime,IServiceProvider serviceProvider)
{
HostApplicationLifetime = hostApplicationLifetime;
ServiceProvider = serviceProvider;
}
public void Dispose()
{
}
public Task StartAsync(CancellationToken cancellationToken)
{
var thread = new Thread(Main);
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
private void Main()
{
WinRT.ComWrappersSupport.InitializeComWrappers();
Application.Start((p) => {
var context = new DispatcherQueueSynchronizationContext(DispatcherQueue.GetForCurrentThread());
SynchronizationContext.SetSynchronizationContext(context);
new TApplication();
});
HostApplicationLifetime.StopApplication();
}
}
}
我在构建设置中定义了 DISABLE_XAML_GENERATED_MAIN
并添加了我自己的 Main
:
public class Program
{
public static void Main(string[] args)
{
Host.CreateDefaultBuilder()
.ConfigureServices(services =>
{
services.AddHostedService<WinUIHostedService<App>>();
})
.Build().Run();
}
}
瞧!即使 IHostedService.StopAsync
运行异步代码,WinUI 应用程序仍然可以正常运行并且主机在主窗口关闭时完全停止。
请注意,此代码只是第一个起作用的东西。它可能会得到改进,我不完全理解通用主机生命周期语义。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。