.NET 通用主机(Generic Host)

.NET 通用主机(Generic Host)

此为系列文章,对MSDN ASP.NET Core 的官方文档进行系统学习与翻译。其中或许会添加本人对 ASP.NET Core 的浅显理解。

这篇文章介绍了.NET Core通用主机,并提供了如何使用它的一些指南。

什么是主机?

    主机是封装了app资源的一些对象,比如:

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

       当一个主机启动时,它会首先在DI容器中查找所有的IHostedService实现,然后在每个找到的实现上调用它的IHostedService.StartAsync方法。在一个web app中,IHostedService的实现之一便是web 服务器,它启动了一个HTTP server implementation

       将所有app需要的资源包含进一个对象的主要原因便是生命周期管理:在app启动时进行控制并优雅地关闭。

       在ASP.NET Core 3.0以前的版本中,Web Host被用来做HTTP工作负载。从ASP.NET Core 3.0开始,Web Host不再推荐为web app所用,其现在仅用作向后兼容。

建立一个主机

      典型的,一个主机在Program.Main方法里进行配置,建立,运行:

  • 调用CreateHostBuilder来创建和配置一个建造者对象。
  • 在建造者对象上调用Build,Run方法。

       这里是一个非HTTP工作负载的Program.cs代码,并且将一个IHostedService实现添加进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<Worker>();
            });
}

        对于一个HTTP工作负载,Main方法是相同的,但是CreateHostBuilder调用了ConfigureWebHostDefaults

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

       如果app使用了Entity Framework Core,请不要更改CreateHostBuilder方法的名称以及签名。Entity Framework Core tools这个工具期望找到一个CreateHostBuilder方法来配置主机,而不用运行app。更多信息,请参考Design-time DbContext Creation

默认建造者设置

       CreateDefaultBuilder方法:

  • GetCurrentDirectory方法返回的路径设置内容根。
  • 从下列位置加载目录配置:具有“DOTNET_”前缀的环境变量,命令行参数。
  • 从下列位置加载app配置:appsettings.jsonappsettings.{Environment}.json,当app运行在开发环境中时的Secret Manager,环境变量,命令行参数。
  • 添加如下的日志提供器:Console,Debug,EventSource,EventLog(仅当运行在Windows上)。
  • 当在开发环境中时,启用域验证以及依赖验证。

      ConfigureWebHostDefaults方法:

       本章后续的两个章节Settings for all app types 以及 Settings for web apps 展示了如何重载默认的建造者设置。

框架提供的服务

      自动注册的服务包含如下:               

     关于框架提供的服务的更多信息,请参考Dependency injection in ASP.NET Core

接口IHostApplicationLifetime

       将IHostApplicationLifetime接口注入到任何类以处理启动后(post-startup)以及优雅的关闭这些任务。这个接口的三个属性是用来注册app开始及 停止事件处理方法的取消标记。这个接口也包含了一个StopApplication方法。

      如下示例是一个注册了IHostApplicationLifetime事件的IHostedService的实现:

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的实现。ConsoleLifetime

 接口IHostEnvironment

         将IHostEnvironment服务注入到一个类中可以获取下列信息:         

       web app实现了这个接口,其继承了IHostEnvironment并添加了WebRootPath

主机配置

       主机配置用作IHostEnvironment实现的属性。

       主机配置从在ConfigureAppConfiguration内部的HostBuilderContext.Configuration可用。在ConfigureAppConfiguration之后,HostBuilderContext.Configuration便被app.config所代替。

       为了添加主机配置,我们可以调用IHostBuilderConfigureHostConfiguration方法。ConfigureHostConfiguration方法可以被调用多次以产生额外的结果。对于一个给定的值,主机会使用最后一次设置它的值的那个选项。

       具有前缀DOTNET_的环境变量提供器以及命令行参数被包含在CreateDefaultBuilder中。对于web app来说,具有前缀ASPNETCORE_的环境变量提供器被添加。当读取环境变量时会移除它们的前缀。举个例子,ASPNETCORE_ENVIRONMENT环境变量值将会变成主机配置值:键environment

       如下示例创建了主机配置:

// using Microsoft.Extensions.Configuration;

Host.CreateDefaultBuilder(args)
    .ConfigureHostConfiguration(configHost =>
    {
        configHost.SetBasePath(Directory.GetCurrentDirectory());
        configHost.AddJsonFile("hostsettings.json", optional: true);
        configHost.AddEnvironmentVariables(prefix: "PREFIX_");
        configHost.AddCommandLine(args);
    });

app配置

        通过调用IHostBuilderConfigureAppConfiguration来创建app配置。ConfigureAppConfiguration方法可以被调用多次以产生额外的结果。对于一个给定的值,主机会使用最后一次设置它的值的那个选项。

        ConfigureAppConfiguration创建的配置在HostBuilderContext.Configuration中可用做后续的操作以及作为一个从DI获取的服务,主机配置也被加进app配置中。

        更多信息,请参考Configuration in ASP.NET Core

 所有app类型的设置

        这个章节列举了应用于HTTP以及非HTTP工作负载的一些主机设置。默认的,用于配置这些设置的环境变量具有DOTNET_ 或者ASPNETCORE_前缀。

ApplicationName

        在主机构造时,通过主机配置来设置IHostEnvironment.ApplicationName

        键:applicationName

        类型:字符串

        默认值:包含了app入口点的程序集的名称。

        环境变量:<PREFIX_>APPLICATIONNAME

        可以使用环境变量来设置此值。

ContentRootPath

        IHostEnvironment.ContentRootPath属性决定了主机从哪儿开始来搜索内容文件。如果路径不存在,那么主机便不会启动。

        键:contentRoot

        类型:字符串

        默认值:app程序集所在的文件夹

        环境变量:<PREFIX_>CONTENTROOT

        可以使用环境变量或者调用IHostBuilderUseContentRoot来设置此值。

Host.CreateDefaultBuilder(args)
    .UseContentRoot("c:\content-root")
    //...

       更多信息,请参考: 

ShutdownTimeout

        HostOptions.ShutdownTimeoutStopAsync 方法设置超时时间。默认值是5秒。在超时期间,主机:

      如果超时时间在所有的寄宿服务 停止之前过期,任何遗留的活动的服务都会在app关闭时候停止,即使它们还没有结束处理。如果服务需要额外的时间来停止,那么就增加超时时间。

      键:shutdownTimeoutSeconds

     类型:整型

     默认值:5秒

     环境变量:<PREFIX_>SHUTDOWNTIMEOUTSECONDS

     使用环境变量或者设置HostOptions来设置此值。下面的示例将超时时间设置为20秒:

Host.CreateDefaultBuilder(args)
    .ConfigureServices((hostContext, services) =>
    {
        services.Configure<HostOptions>(option =>
        {
            option.ShutdownTimeout = System.TimeSpan.FromSeconds(20);
        });
    });

 web app的设置

       一些主机设置仅仅应用于HTTP工作负载。默认的,用于配置这些设置的环境变量都具有DOTNET_ 或者 ASPNETCORE_前缀。

       IWebHostBuilder上的扩展方法对于这些设置是可用的。展示如何调用扩展方法的代码示例假设webBuilderIWebHostBuilder的一个实例。比如如下代码:

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

CaptureStartupErrors

       当设置为false时,启动时的错误会导致主机存在。当设置为true时,主机捕获启动时的异常并试图开始服务。

       键:captureStartupErrors

       类型:布尔

       默认值:默认为false,除非app运行在IIS之下的Kestrel中,此时默认值为true。

       环境变量:<PREFIX_>CAPTURESTARTUPERRORS

       使用配置或者调用CaptureStartupErrors来设置此值:

webBuilder.CaptureStartupErrors(true);

DetailedErrors

        当启用时,或者当环境为开发环境时,app会捕获详细的错误信息。

        键:detailedErrors

        类型:布尔

        默认值:false

        环境变量:<PREFIX_>_DETAILEDERRORS

        使用配置或者调用UseSetting来设置此值:

webBuilder.UseSetting(WebHostDefaults.DetailedErrorsKey, "true");

HostStartupAssemblies

      主机启动程序集是以分号隔开的,它会在启动的时候被加载。虽然配置值默认为一个空字符串,主机启动程序集总是包含app的程序集。当提供了主机启动程序集时当app在开始阶段构建它的通用服务时,它们会被添加到app的程序集中。

      键:hostingStartupAssemblies

      类型:字符串

      默认值:空字符串

      环境变量:<PREFIX_>_HOSTINGSTARTUPASSEMBLIES

      使用配置或者调用UseSetting来设置此值:

webBuilder.UseSetting(WebHostDefaults.HostingStartupAssembliesKey, "assembly1;assembly2");

HostingStartupExcludeAssemblies

       在app开始时,被排除的以分号隔开的主机启动程序集。

       键:hostingStartupExcludeAssemblies

      类型:字符串

      默认值:空字符串

      环境变量:<PREFIX_>_HOSTINGSTARTUPEXCLUDEASSEMBLIES

      使用配置或者调用UseSetting来设置此值:

webBuilder.UseSetting(WebHostDefaults.HostingStartupExcludeAssembliesKey, "assembly1;assembly2");

HTTPS_Port

       HTTPS重定向端口。使用在enforcing HTTPS之中。

      键:https_port

      类型:字符串

      默认值:无默认值

      环境变量:<PREFIX_>HTTPS_PORT

      使用配置或者调用UseSetting来设置此值:

webBuilder.UseSetting("https_port", "8080");

PreferHostingUrls

          指示主机是否要监听使用IWebHostBuilder配置的URLs,而不是使用IServer实现配置的URLs.

          键:preferHostingUrls

         类型:布尔

         默认值:true

         环境变量:<PREFIX_>_PREFERHOSTINGURLS

        使用配置或者调用PreferHostingUrls来设置此值:

webBuilder.PreferHostingUrls(false);

PreventHostingStartup

      阻止主机启动程序的自动加载,包括由app的程序集配置的主机启动程序集。更多信息,请参考Use hosting startup assemblies in ASP.NET Core

         键:preventHostingStartup

         类型:布尔

         默认值:false

         环境变量:<PREFIX_>_PREVENTHOSTINGSTARTUP

         使用配置或者调用UseSetting来设置此值:

webBuilder.UseSetting(WebHostDefaults.PreventHostingStartupKey, "true");

StartupAssembly

      用来查找Startup类的程序集。

         键:startupAssembly

         类型:字符串

         默认值:app的程序集

         环境变量:<PREFIX_>STARTUPASSEMBLY

         使用配置或者调用UseStartup来设置此值。UseStartup方法可以使用程序集名称或者一个类型。如果多个UseStartup被调用,最后一个优先考虑。

webBuilder.UseStartup("StartupAssemblyName");
webBuilder.UseStartup<Startup>();

URLs

      以分号隔开的IP地址的列表,或者带有端口和协议的主机地址,服务应该监听它们的请求。举个例子,http://localhost:123。使用“*”来指示服务应该监听来自任何IP地址或者任何带有特定端口和协议的主机名的请求(比如:http://*:5000)。每一个URL都必须包含协议((http:// 或者https://)。支持的格式根据服务的不同会有变化。

         键:urls

         类型:字符串

         默认值:http://localhost:5000 和 https://localhost:5001

         环境变量:<PREFIX_>URLS

         使用配置或者调用UseUrls来设置此值

webBuilder.UseUrls("http://*:5000;http://localhost:5001;https://hostname:5002");

         Kestrel具有自己的终结点配置API。更多信息,请参考Kestrel web server implementation in ASP.NET Core

WebRoot

         应用 程序静态资产的相对路径。

         键:webroot

         类型:字符串

         默认值:wwwroot{content root}/wwwroot 路径必须存在,如果这个路径不存在,便会使用无操作文件提供程序。

         环境变量:<PREFIX_>WEBROOT

         使用配置或者调用UseWebRoot来设置此值

webBuilder.UseWebRoot("public");

        更多信息,请参考:   

管理主机生命周期

     调用内置的IHost实现的方法来启动和停止app。这些方法影响着所有在容器中注册的IHostedService 的实现。

Run

     Run使得app开始运行,并阻塞调用线程直至主机关闭。

RunAsync

     RunAsync 启动app并返回一个Task,当取消标记或触发关闭时其会完成。

RunConsoleAsync

      RunConsoleAsync 启用控制台支持。创建并开启主机。并等待 Ctrl+C/SIGINT 或 SIGTERM 来关闭。

Start

    Start 同步开启一个主机。

StartAsync

    StartAsync 开始一个主机并返回一个Task,当取消标记或触发关闭时其会完成。

    在StartAsync开始时会调用WaitForStartAsync,在继续之前会等待直至StartAsync的完成。这可以用来推迟启动直至收到外部事件的信号。

StopAsync

     StopAsync 试图在给定的超时时间里停止主机。

WaitForShundown

      WaitForShutdown 阻塞调用线程直至IHostLifetime触发了关闭事件,比如通过Ctrl+C/SIGINT 或SIGTERM。

WaitForShutdownAsync

      WaitForShutdownAsync 返回一个可等待的任务,它会在通过给定的标识和调用StopAsync来触发关闭时候完成。

External control

      使用可以从外部调用的方法来达到对主机生命周期直接控制的目的。

public class Program
{
    private IHost _host;

    public Program()
    {
        _host = new HostBuilder()
            .Build();
    }

    public async Task StartAsync()
    {
        _host.StartAsync();
    }

    public async Task StopAsync()
    {
        using (_host)
        {
            await _host.StopAsync(TimeSpan.FromSeconds(5));
        }
    }
}

额外资源