一.概述
ASP.NET Core 通用主机 (HostBuilder),该主机对于托管不处理 HTTP 请求的应用非常有用。通用主机的目标是将 HTTP 管道从 Web 主机 API 中分离出来,从而启用更多的主机方案。 基于通用主机的消息、后台任务和其他非 HTTP 工作负载可从横切功能(如配置、依赖关系注入 [DI] 和日志记录)中受益。通用主机是 ASP.NET Core 2.1 中的新增功能,不适用于 Web 承载方案。通用主机正处于开发阶段,用于在未来版本中替换 Web 主机,并在 HTTP 和非 HTTP 方案中充当主要的主机 API。
通用主机库位于 Microsoft.Extensions.Hosting 命名空间中,而web主机库位于Microsoft.AspNetCore.Hosting命令空间中。
PM> Install-Package Microsoft.AspNetCore.Hosting.Abstractions -Version 2.2.0
1.1 设置主机
IHostBuilder 是供库和应用初始化、生成和运行主机的主要组件。(官方文档中main方法是使用的异步,但本人vs程序启动时提示找不到mian方法,只好改成了同步) 。
public static void Main(string[] args) { var host = new HostBuilder() .Build(); host.Run(); }
1.2 默认服务
在主机初始化期间注册以下服务:
环境 (IHostingEnvironment)
HostBuilderContext
配置 (IConfiguration)
IApplicationLifetime (ApplicationLifetime)
IHostLifetime (ConsoleLifetime)
IHost
选项 (AddOptions)
日志记录 (AddLogging)
1.3 主机配置 ConfigureHostConfiguration
主机配置的创建方式如下:
调用 IHostBuilder 上的扩展方法以设置“内容根”和“环境”。
从 ConfigureHostConfiguration 中的配置提供程序读取配置。
(1) ConfigureHostConfiguration 主机配置
通用主机配置与web主机配置还是有些区别,在通用主机中有ConfigureHostConfiguration用来配置主机。主机配置用于初始化 IHostingEnvironment,以供在应用的构建过程中使用。可多次调用 ConfigureHostConfiguration
,并得到累计结果。必须在 ConfigureHostConfiguration
中显式指定应用所需的任何配置提供程序,包括:
1)文件配置(例如,来自 hostsettings.json 文件)。
2)环境变量配置。
3)命令行参数配置。
4)任何其他所需的配置提供程序。
通过使用 SetBasePath 指定应用的基本路径,然后调用其中一个文件配置提供程序,可以启用主机的文件配置。
(2) AddEnvironmentVariables 环境变量
要添加主机的环境变量配置,请在主机生成器上调用 AddEnvironmentVariables。 示例应用使用前缀 PREFIX_
。 当系统读取环境变量时,便会删除前缀。 配置示例应用的主机后,PREFIX_ENVIRONMENT
的环境变量值就变成 environment
密钥的主机配置值。
(3) AddCommandLine 命令行参数
通过 dotnet run
运行应用 指定参数时,通过调用 AddCommandLine 可添加命令行配置。
1.4 应用配置 ConfigureAppConfiguration
调用 ConfigureAppConfiguration 创建应用配置,在web主机中也有介绍。这里就不再说明。 主机配置和应用配置都可以做配置使用,主机配置重点在主机环境的配置(IHostingEnvironment)。
1.5 ConfigureServices
ConfigureServices 将服务添加到应用的依赖关系注入容器。 可多次调用 ConfigureServices,并得到累计结果。这个在web主机中常用。 值得注意的是:除了三种注入的实例生命周期(asp.net core 系列 4 注入服务的生存期)。还可以注入THostedService类型服务,专门用于做后台服务的。
var host = new HostBuilder() .ConfigureServices((hostContext, services) => { if (hostContext.HostingEnvironment.IsDevelopment()) { // Development service configuration } else { // Non-development service configuration } services.AddHostedService<LifetimeEventsHostedService>(); services.AddHostedService<TimedHostedService>(); })
1.6 IApplicationLifetime 接口
IApplicationLifetime接口在上篇介绍web主机进有讲过,这里不在具体介绍。下面会有代码演示,实现一个IHostedService类型服务,在服务中用于注册事件。
二. 完整示例
使用通用主机来演示一个后台服务。使用控制台做宿主,后台服务定时每隔5秒执行一次。该演示包括主机配置、应用配置、服务容器注入、日志配置。还包括注入二个IHostedService类型的服务。其中TimedHostedService类用于做后台定时服务,LifetimeEventsHostedService类注入服务IApplicationLifetime事件,监听服务运行状态。
完整示例github地址:
public class Program { /// <summary> /// 使用控制台做承载的后台服务 /// </summary> /// <param name="args"></param> public static void Main(string[] args) { var host = new HostBuilder() .ConfigureHostConfiguration(configHost => { configHost.SetBasePath(Directory.GetCurrentDirectory()); configHost.AddJsonFile("hostsettings.json", optional: true); configHost.AddEnvironmentVariables(prefix: "PREFIX_"); configHost.AddCommandLine(args); }) .ConfigureAppConfiguration((hostContext, configApp) => { configApp.AddJsonFile("appsettings.json", optional: true); configApp.AddJsonFile( $"appsettings.{hostContext.HostingEnvironment.EnvironmentName}.json", optional: true); configApp.AddEnvironmentVariables(prefix: "PREFIX_"); configApp.AddCommandLine(args); }) .ConfigureServices((hostContext, services) => { //注册后台普通服务 // services.AddSingleton<IJobTimeService, JobTimeService>(); //注册后台THostedService类型服务 services.AddHostedService<LifetimeEventsHostedService>(); services.AddHostedService<TimedHostedService>(); }) .ConfigureLogging((hostContext, configLogging) => { configLogging.AddConsole(); configLogging.AddDebug(); }) .UseConsoleLifetime() .Build(); //实例化注入的普通服务 // IJobTimeService job = host.Services.GetRequiredService<IJobTimeService>(); // job.Time(); host.Run(); } }
/// <summary> ///监听服务运行状态 /// </summary> internal class LifetimeEventsHostedService : IHostedService { private readonly ILogger _logger; private readonly IApplicationLifetime _appLifetime; public LifetimeEventsHostedService( ILogger<LifetimeEventsHostedService> logger, IApplicationLifetime appLifetime) { _logger = logger; _appLifetime = appLifetime; } public Task StartAsync(CancellationToken cancellationToken) { _appLifetime.ApplicationStarted.Register(OnStarted); _appLifetime.ApplicationStopping.Register(OnStopping); _appLifetime.ApplicationStopped.Register(OnStopped); return Task.CompletedTask; } public Task StopAsync(CancellationToken cancellationToken) { return Task.CompletedTask; } private void OnStarted() { _logger.LogInformation("OnStarted has been called."); // Perform post-startup activities here } private void OnStopping() { _logger.LogInformation("OnStopping has been called."); // Perform on-stopping activities here } private void OnStopped() { _logger.LogInformation("OnStopped has been called."); // Perform post-stopped activities here } }
/// <summary> /// 后台定时服务 /// </summary> internal class TimedHostedService : IHostedService, IDisposable { private readonly ILogger _logger; private Timer _timer; public TimedHostedService(ILogger<TimedHostedService> logger) { _logger = logger; } public Task StartAsync(CancellationToken cancellationToken) { _logger.LogInformation("Timed Background Service is starting."); _timer = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromSeconds(5)); return Task.CompletedTask; } /// <summary> /// 每隔5秒执行一次 /// </summary> /// <param name="state"></param> private void DoWork(object state) { _logger.LogInformation("Timed Background Service is working."); } public Task StopAsync(CancellationToken cancellationToken) { _logger.LogInformation("Timed Background Service is stopping."); _timer?.Change(Timeout.Infinite, 0); return Task.CompletedTask; } public void Dispose() { _timer?.Dispose(); } }
-- hostsettings.json文件 { "environment": "Development" }
参考文献:
官方文档:ASP.NET Core 通用主机