为了账号安全,请及时绑定邮箱和手机立即绑定

为什么调用 IHost.StopAsync 时会调用

为什么调用 IHost.StopAsync 时会调用

C#
萧十郎 2023-08-20 10:18:49
假设以下使用通用主机的 .NET Core 2.2 控制台应用程序:using Microsoft.Extensions.DependencyInjection;using Microsoft.Extensions.Hosting;using System;using System.Threading;using System.Threading.Tasks;namespace SimpleGenericHost{    class SimpleHostedService : IHostedService    {        public Task StartAsync(CancellationToken cancellationToken)        {            Console.WriteLine("Service started");            return Task.CompletedTask;        }        public Task StopAsync(CancellationToken cancellationToken)        {            Console.WriteLine("Service stopped");            return Task.CompletedTask;        }    }    class Program    {        static async Task Main(string[] args)        {            var host = new HostBuilder()                .ConfigureServices(services =>                {                    services.AddHostedService<SimpleHostedService>();                })                .Build();            var runTask = host.RunAsync();            await Task.Delay(5000);            await host.StopAsync();            await runTask;        }    }}当您运行它时,将输出以下内容:Service startedApplication started. Press Ctrl+C to shut down.Hosting environment: ProductionContent root path: C:\projects\ConsoleApps\SimpleGenericHost\bin\Debug\netcoreapp2.2\Service stoppedService stopped正如你所看到的,SimpleHostedService.StopAsync被调用了两次。为什么?这是预期的吗?我错过了什么吗?IHostedService.StopAsync还有另一种方法可以停止只被调用一次的主机吗?
查看完整描述

1 回答

?
噜噜哒

TA贡献1784条经验 获得超7个赞

因为它被调用了两次——一次是在延迟之后,另一次是在服务实际停止时。RunAsync它并不意味着在使用时被调用。


要在超时后停止,请使用带有超时的 CancellationTokenSource 并将其令牌传递给RunAsync:


var timeoutCts=new CancellationTokenSource(5000);


await host.RunAsync(timeoutCts.Token);

解释


StopAsync 不会停止服务,它用于通知服务需要停止。当应用程序停止时,它由托管服务基础设施本身调用。


.NET Core 是开源的,这意味着您可以检查RunAsync 源。RunAsync启动主机,然后等待终止:


await host.StartAsync(token);


await host.WaitForShutdownAsync(token);

WaitForShutdownAsync方法侦听来自控制台或通过显式调用的终止请求IHostApplicationLifetime.StopApplication。当这种情况发生时,它会调用StopAsync自己:


await waitForStop.Task;


// Host will use its default ShutdownTimeout if none is specified.

await host.StopAsync();

如果您打算自己管理应用程序的生命周期,则应该使用StartAsync而不是。RunAsync


但在这种情况下,您只需在超时时停止应用程序。您可以通过CancellationTokenSource(int)构造函数将取消令牌传递给RunAsync仅在超时后触发的取消令牌,从而轻松地做到这一点:


var timeoutCts=new CancellationTokenSource(5000);


await host.RunAsync(timeoutCts.Token);


查看完整回答
反对 回复 2023-08-20
  • 1 回答
  • 0 关注
  • 109 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信