1

考虑这个没有特殊配置或托管服务的极其简单的 .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();
    }

第一次运行(仅出于本测试的目的作为后台触发和忘记任务发送)和停止成功完成。在第二次调用 Run 时,我收到此异常:

System.AggregateException:'对象名称:'EventLogInternal'。无法访问已处置的对象。对象名称:'EventLogInternal'。)'

如果我做同样的事情但使用 StartAsync 而不是 RunAsync(这次不需要 fireAndForget),我会System.OperationCanceledException第二次收到一个名为 StartAsync 的消息。

我是否可以推断出 .NET 通用主机不应该被停止和重新启动?

为什么我需要这个?

我的目标是让单个应用程序作为 Windows 服务运行,该服务将托管两个不同的 .NET 通用主机。这是基于此处的建议,以便拥有单独的配置和依赖注入规则以及消息队列。

一个将在所有应用程序生命周期内保持活动状态(直到服务在 Windows 服务中停止),并将用作接收消息事件的入口点,该消息事件将启动/停止另一个将是具有完整服务的主要处理主机。这样,主要服务可以处于“空闲”状态,直到它们收到触发其进程的消息,并且另一条消息可以将它们返回到空闲状态。

4

1 回答 1

1

返回的主机CreateDefaultBuilder(...).Build()是为了代表整个应用程序。来自文档

将应用程序的所有相互依赖资源包含在一个对象中的主要原因是生命周期管理:控制应用程序启动和正常关闭。

默认构建器在单例范围内注册了许多服务,当主机停止时,所有这些服务都被释放或切换到某种“停止”状态。例如,在致电之前,StopAsync您可以解决IHostApplicationLifetime

var appLifetime = host.Services.GetService<IHostApplicationLifetime>();

它具有代表应用程序状态的取消标记。当您在停止后调用 StartAsync 或 RunAsync 时,所有令牌仍IsCancellationRequested设置为true. 这就是在Host.StartAsyncOperactionCancelledException中抛出的原因。

您可以在配置期间列出其他服务: 在此处输入图像描述

对我来说,听起来您只需要一些后台作业来处理消息,但我从未使用过 NServiceBus,所以我不知道它如何与 Hangfire 之类的东西一起使用。您还可以IHostedService在通用主机构建器中实现和使用它。

于 2020-11-02T19:15:22.043 回答