ASP.NET Core 入门——主机(Host)

989 阅读3分钟

什么是主机

主机是封装了应用程序资源的对象,例如:

  • 依赖注入
  • 日志
  • 配置
  • IHostedService的实现

当主机启动时,会从DI容器中找到IHostedService接口的所有实现,并调用IHostedService.StartAsync方法。如果是web应用,IHostedService的其中一个实现就是一个web服务,它会启动一个HTTP服务器实现,视情况的不同,HTTP服务器实现可能是Kestrel,IIS HTTP Server或HTTP.sys三者之一,关于此可以查看ASP.NET Core的几种托管方式

将应用的所有依赖资源包含在一个对象中的主要考虑是:优雅地控制应用的启动和停止。

在ASP.NET Core 3.0之前的版本中,Web Host用来处理HTTP负载。现在,Web Host已经不推荐使用了,它的存在只是为了向前兼容。

启动主机

通常,主机在Program类中配置,构建并运行。在Main方法中:

  • 调用CreateHostBuilder方法创建并配置一个builder对象。
  • 调用builder对象的Build以及Run方法。

下面是不处理HTTP负载的例子,在DI容器中有一个IHostedService的实现:

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<Worker>();
            });
}

对于有HTTP负载的情况,Main方法还是一样,不过CreateHostBuilder调用了ConfigureWebHostDefaults:

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup<Startup>();
        });

假如应用要使用Entity Framework Core,不要修改CreateHostBuilder方法的签名,因为Entity Framework Core工具要在不运行应用的情况下配置主机需要找到一个CreateHostBuilder方法。

默认的builder配置

CreateDefaultBuilder方法:

  • 将内容根设置为GetCurrentDirectory返回的路径
  • 从下列位置加载主机配置:
    • 带有 "DOTNET_"前缀的环境变量。
    • 命令行参数。
  • 从下列位置加载app配置:
    • appsettings.json
    • appsettings.{Environment}.json
    • Secret Manager(如果在开发环境中运行)
    • 环境变量
    • 命令行参数
  • 添加下列的日志支持:
    • 控制台
    • Debug
    • EventSource
    • EventLog(仅Windows)
  • 在开发环境中启用scope validation和dependency validation

ConfigureWebHostDefaults方法:

  • 从带有"ASPNETCORE_"前缀的环境变量中加载主机配置
  • 将Kestrel设为Web服务器并使用应用的主机配置提供程序配置
  • 添加主机过滤器中间件
  • 如果ASPNETCORE_FORWARDEDHEADERS_ENABLED=true,添加Forwarded Headers中间件
  • 启用IIS集成

框架自带服务

自动注册了以下服务:

  • IHostApplicationLifetime
  • IHostLifetime
  • IHostEnvironment / IWebHostEnvironment

IHostApplicationLifetime

IHostApplicationLifetime以前叫IApplicationLifetime,将该服务注入到任何类里,可以用来处理应用程序生命周期事件(启动和停止)。 该接口还包括一个StopApplication 方法。

下面的例子是一个IHostedService接口的实现,并注册了IHostApplicationLifetime事件:

internal class LifetimeEventsHostedService : IHostedService
{
    private readonly ILogger _logger;
    private readonly IHostApplicationLifetime _appLifetime;

    public LifetimeEventsHostedService(
        ILogger<LifetimeEventsHostedService> logger, 
        IHostApplicationLifetime 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
    }
}

IHostLifetime

IHostLifetime的实现控制什么时候启动和停止主机,使用最后注册的那个实现,这意味着可以重写默认实现。

Microsoft.Extensions.Hosting.Internal.ConsoleLifetime是IHostLifetime的默认实现,它:

  • 监听Ctrl+C/SIGINT或SIGTERM并调用StopApplication启动关闭进程
  • 非阻塞的扩展方法,例如RunAsync以及WaitForShutdownAsync

IHostEnvironment

注入该服务可以获取如下信息:

  • 应用名称
  • 环境名称
  • 内容根路径

Web应用实现了IWebHostEnvironment接口,该接口继承了IHostEnvironmentbiang,并新增了一个WebRootPath。