在 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()
几乎总是一个坏主意,因为它可能会导致死锁。
我有一个 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()
几乎总是一个坏主意,因为它可能会导致死锁。