.NET 通用主机 - 是否可以停止并重新启动主机?
.NET Generic Host - Is it possible to stop and restart a host?
考虑这个没有特殊配置或托管服务的极其简单的 .NET Core 3.1(和 .NET 5)应用程序:
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
internal class Program
{
public static async Task Main(string[] args)
{
var builder = Host.CreateDefaultBuilder(args);
builder.UseWindowsService();
var host = builder.Build();
var fireAndforget = Task.Run(async () => await host.RunAsync());
await Task.Delay(5000);
await host.StopAsync();
await Task.Delay(5000);
await host.RunAsync();
}
第一个 运行(仅出于本次测试的目的作为后台触发和忘记任务发送)和停止成功完成。第二次调用 运行 时,我收到此异常:
System.AggregateException : 'Object name: 'EventLogInternal'.Cannot access a disposed object. Object name: 'EventLogInternal'.)'
如果我这样做但使用 StartAsync 而不是 运行Async(这次不需要 fireAndForget),我会在第二次调用 StartAsync 时收到 System.OperationCanceledException
。
我推断 .NET Generic Host 不应该停止和重新启动是否正确?
为什么我需要这个?
我的目标是将单个应用程序 运行 作为 Windows 服务来托管两个不同的 .NET 通用主机。这是基于 here 的建议,以便具有单独的配置和依赖项注入规则和消息队列。
一个将在整个应用程序生命周期内保持活动状态(直到服务在 Windows 服务中停止)并将作为接收消息事件的入口点,该消息事件将 start/stop 另一个将是提供完整服务的主要处理主机。这样,主要服务可以处于“空闲”状态,直到它们收到触发其进程的消息,而另一条消息可以 return 它们进入空闲状态。
CreateDefaultBuilder(...).Build()
返回的主机代表整个应用程序。来自 docs:
The main reason for including all of the app's interdependent resources in one object is lifetime management: control over app startup and graceful shutdown.
默认构建器在单例范围内注册许多服务,当主机停止时,所有这些服务都将被处理或切换到某种“停止”状态。例如,在调用 StopAsync
之前,您可以解析 IHostApplicationLifetime
:
var appLifetime = host.Services.GetService<IHostApplicationLifetime>();
它有代表应用程序状态的取消标记。当您在停止后调用 StartAsync 或 RunAsync 时,所有标记仍将 IsCancellationRequested
设置为 true
。这就是 OperactionCancelledException
在 Host.StartAsync.
中被抛出的原因
您可以在配置期间列出其他服务:
对我来说,听起来您只需要一些后台作业来处理消息,但我从未使用过 NServiceBus,所以我不知道它如何与 Hangfire 之类的东西一起工作。您还可以实施 IHostedService
并在通用主机构建器中使用它。
我正在做类似的事情:
do
{
using IHost host = BuildHost();
await host.RunAsync();
} while (MainService.Restart);
使用 MainService 构造函数:
public MainService(IHostApplicationLifetime HostApplicationLifetime)
MainService.Restart
是由 MainService
本身设置的静态布尔值,以响应也调用 HostApplicationLifetime.StopApplication()
.
的某些事件
考虑这个没有特殊配置或托管服务的极其简单的 .NET Core 3.1(和 .NET 5)应用程序:
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
internal class Program
{
public static async Task Main(string[] args)
{
var builder = Host.CreateDefaultBuilder(args);
builder.UseWindowsService();
var host = builder.Build();
var fireAndforget = Task.Run(async () => await host.RunAsync());
await Task.Delay(5000);
await host.StopAsync();
await Task.Delay(5000);
await host.RunAsync();
}
第一个 运行(仅出于本次测试的目的作为后台触发和忘记任务发送)和停止成功完成。第二次调用 运行 时,我收到此异常:
System.AggregateException : 'Object name: 'EventLogInternal'.Cannot access a disposed object. Object name: 'EventLogInternal'.)'
如果我这样做但使用 StartAsync 而不是 运行Async(这次不需要 fireAndForget),我会在第二次调用 StartAsync 时收到 System.OperationCanceledException
。
我推断 .NET Generic Host 不应该停止和重新启动是否正确?
为什么我需要这个?
我的目标是将单个应用程序 运行 作为 Windows 服务来托管两个不同的 .NET 通用主机。这是基于 here 的建议,以便具有单独的配置和依赖项注入规则和消息队列。
一个将在整个应用程序生命周期内保持活动状态(直到服务在 Windows 服务中停止)并将作为接收消息事件的入口点,该消息事件将 start/stop 另一个将是提供完整服务的主要处理主机。这样,主要服务可以处于“空闲”状态,直到它们收到触发其进程的消息,而另一条消息可以 return 它们进入空闲状态。
CreateDefaultBuilder(...).Build()
返回的主机代表整个应用程序。来自 docs:
The main reason for including all of the app's interdependent resources in one object is lifetime management: control over app startup and graceful shutdown.
默认构建器在单例范围内注册许多服务,当主机停止时,所有这些服务都将被处理或切换到某种“停止”状态。例如,在调用 StopAsync
之前,您可以解析 IHostApplicationLifetime
:
var appLifetime = host.Services.GetService<IHostApplicationLifetime>();
它有代表应用程序状态的取消标记。当您在停止后调用 StartAsync 或 RunAsync 时,所有标记仍将 IsCancellationRequested
设置为 true
。这就是 OperactionCancelledException
在 Host.StartAsync.
您可以在配置期间列出其他服务:
对我来说,听起来您只需要一些后台作业来处理消息,但我从未使用过 NServiceBus,所以我不知道它如何与 Hangfire 之类的东西一起工作。您还可以实施 IHostedService
并在通用主机构建器中使用它。
我正在做类似的事情:
do
{
using IHost host = BuildHost();
await host.RunAsync();
} while (MainService.Restart);
使用 MainService 构造函数:
public MainService(IHostApplicationLifetime HostApplicationLifetime)
MainService.Restart
是由 MainService
本身设置的静态布尔值,以响应也调用 HostApplicationLifetime.StopApplication()
.