如何实现只运行一次的.net core IHostedService

MiD*_*Daa 5 c# .net-core

我知道IHostedService只运行一次的 a 听起来像控制台应用程序,但我想使用它而不是普通控制台应用程序的原因是:

  • .net core 引入Generic Host来运行非 http 应用程序
  • 一个普通的控制台应用程序没有准备好使用的 DI、记录器、配置

通过使用以下代码,我可以在一定程度上实现这种一次性行为,但是,我找不到在应用程序完成后正常退出应用程序的方法。

public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureServices((hostContext, services) => { services.AddHostedService<StartUp>(); });
    }
Run Code Online (Sandbox Code Playgroud)

哪里StartUp有简单的IHostedService

public class StartUp:IHostedService
    {
        private ILogger<StartUp> _logger;

        public StartUp(ILogger<StartUp> logger)
        {
            _logger = logger;
        }

        public Task StartAsync(CancellationToken cancellationToken)
        {
            _logger.LogInformation("start async");
            return Task.CompletedTask;
        }

        public Task StopAsync(CancellationToken cancellationToken)
        {
            _logger.LogInformation("stop async");
            return Task.CompletedTask;
        }
    }
Run Code Online (Sandbox Code Playgroud)

如何优雅地停止应用程序?或者如果这是完全错误的,我应该如何实现这个一次性应用程序?

Ole*_*egI 9

是的,您可以通过注入IHostApplicationLifetime您的托管服务来实现这一点。

例子:

 public class StartUp:IHostedService
 {
    private readonly IHostApplicationLifetime _host;
    private ILogger<StartUp> _logger;

    public StartUp(IHostApplicationLifetime host, ILogger<StartUp> logger)
    {
        _host = host;
        _logger = logger;
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("start async");
        _host.StopApplication();
        return Task.CompletedTask;
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("stop async");
        return Task.CompletedTask;
    }
}
Run Code Online (Sandbox Code Playgroud)

您还可以通过设置退出代码Environment.ExitCode。例如:

Environment.ExitCode = 0;
_host.StopApplication();
Run Code Online (Sandbox Code Playgroud)


Mar*_*tin 9

如果您只是IHostedService用作缺少 DI 的解决方法,并且ILogger您也可以使用ILoggerIConfiguration直接设置 DI,而无需IHostedService

public class Program
{
    public static async Task Main(string[] args)
    {
        var configBuilder = new ConfigurationBuilder()
                                .AddJsonFile("appsettings.json", optional: true);
        var config = configBuilder.Build();

        var sp = new ServiceCollection()
            .AddLogging(b => b.AddConsole())
            .AddSingleton<IConfiguration>(config)
            .AddSingleton<IFooService, FooService>()
            .BuildServiceProvider();

        var logger = sp.GetService<ILoggerFactory>().CreateLogger<Program>();
        logger.LogDebug("Starting");

        var bar = sp.GetService<IFooService>();
        await bar.DoAsync();
    }
}
Run Code Online (Sandbox Code Playgroud)

使用此设置,您的代码只需运行一次,即可解析您注册的所有服务ServiceCollection,无需Host启动

示例:.netfiddle