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

假设以下使用通用主机的 .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 started

Application started. Press Ctrl+C to shut down.

Hosting environment: Production

Content root path: C:\projects\ConsoleApps\SimpleGenericHost\bin\Debug\netcoreapp2.2\

Service stopped

Service stopped

正如你所看到的,SimpleHostedService.StopAsync被调用了两次。为什么?


这是预期的吗?我错过了什么吗?IHostedService.StopAsync还有另一种方法可以停止只被调用一次的主机吗?


萧十郎
浏览 110回答 1
1回答

噜噜哒

因为它被调用了两次——一次是在延迟之后,另一次是在服务实际停止时。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);
打开App,查看更多内容
随时随地看视频慕课网APP