在 WPF 应用程序中托管 ASP Web Api 不会正常停止

Hosting an ASP Web Api inside a WPF app wont stop gracefully

我有一个 Asp 核心 3.1 应用托管休息 API。它可以 运行 独立,但我有一个 WPF 应用程序,我希望它也能够在 运行ning 时托管其余 API。

我已经开始工作了,但我的问题是当我关闭我的最后一个 WPF window 时,我告诉 ASP 的 IHost 关闭并且它使进程保持打开状态。我只做了一些修改就用全新的项目重现了这个问题:

在 WPF 项目中,我删除了 StartupURI 并使用启动和退出事件:

 private void Application_Startup(object sender, StartupEventArgs e)
 {
     RestApiProgram.StartAsync(CancellationToken.None).GetAwaiter().GetResult();
     MainWindow window = new MainWindow();
     window.Show();
 }

 private void Application_Exit(object sender, ExitEventArgs e)
 {
     RestApiProgram.StopAsync(CancellationToken.None).GetAwaiter().GetResult();
 }

在 Asp 项目中,我修改了程序 class 以便我可以在 IHost 上调用启动和停止:

 private static IHost _host;
 //Main is called when running the ASP project by itself
 public static void Main(string[] args)
 {
     CreateHostBuilder(args).Build().Run();
 }

 public static IHostBuilder CreateHostBuilder(string[] args) =>
     Host.CreateDefaultBuilder(args)
         .ConfigureWebHostDefaults(webBuilder =>
         {
             webBuilder.UseStartup<Startup>();
         });

 //StartAsync is called by the WPF app
 public static Task StartAsync(CancellationToken token)
 {
     _host = CreateHostBuilder(Array.Empty<string>()).Build();
     return _host.StartAsync(token);
 }

 public static async Task StopAsync(CancellationToken token)
 {
     using (_host)
     {
         await _host.StopAsync(token);
     }
 }

当我关闭主 window 时,我的 WPF 应用程序调用 StopAsync,我在输出中看到消息“Microsoft.Hosting.Lifetime:信息:应用程序正在关闭...”,但是进程不关闭。当我暂停时,它会卡住等待 StopAsync 完成。有什么想法吗?

您应该等待 StopAsync 返回的 Task

要防止 WPF 应用程序在任务完成之前关闭,您可以处理 window 的 OnClosing 事件:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        this.Closing += WhenClosing;
    }
    ...

    private async void WhenClosing(object sender, System.ComponentModel.CancelEventArgs e)
    {
        e.Cancel = true;
        await RestApiProgram.StopAsync(CancellationToken.None);
        this.Closing -= WhenClosing;
        Close();
    }
}

StartAsync也是如此:

private async void Application_Startup(object sender, StartupEventArgs e)
{
    await RestApiProgram.StartAsync(CancellationToken.None);
    MainWindow window = new MainWindow();
    window.Show();
 }

调用 .GetAwaiter().GetResult() 几乎总是一个坏主意,因为它可能会导致死锁。