翻譯 - ASP.NET Core 基本知識 - 通用主機 (Generic Host)

sims發表於2021-01-24

翻譯自 https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/generic-host?view=aspnetcore-5.0

ASP.NET Core 模板建立了一個 .NET Core 通用主機 (Generic Host HostBuilder)。

本話題提供了關於在 ASP.NET Core 中使用 .NET 通用主機。關於在控制檯中使用 .NET Generic Host 的資訊,檢視 .NET Generic Host

主機定義

主機是指封裝了應用程式資源的物件,例如:

  • 依賴注入(DI)
  • 日誌
  • 配置
  • IHostedService 實現

當一個主機啟動的時候,它會呼叫 IHostedService.StartAsync 在每一個在服務容器中託管服務集合中註冊的 IHostedService 的實現。 在 Web 應用程式中,一個 IHostedService 的實現是一個啟動 HTTP server implementation 的 web 服務。

包含所有的應用程式相互依賴的資源在一個物件中的主要原因是宣告週期管理:控制應用程式啟動和優雅的關閉。

設定一個主機

主機一般在 Program 類中通過程式碼配置,建立,執行。Main 方法:

  • 呼叫 CreateHostBuilder 方法建立和配置一個 builder 物件
  • 在 builder 物件上呼叫 Build 和 Run 方法

ASP.NET Core web 模板生成下列程式碼建立一個主機:

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

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

下面的程式碼建立一個 non-HTTP 工作負載,將一個 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>();
        });

如果應用程式使用了 Entity Framework Core,不要改變 CreateHostBuiler 方法的名稱和簽名。Entity Framework Core tools 期望發現一個 CreateHostBuilder 方法,不用執行應用程式就可以配置主機(Host)。更多資訊,檢視 Design-time DbContext Creation

預設 builder 設定

CreateDefaultBuilder 方法:

  • 設定內容根目錄(content root)為 GetCurrentDirectory 返回的路徑
  • 從以下地方載入主機配置:
    字首為 DOTNET_  的環境變數
    命令列引數
  • 從以下地方載入應用程式配置:
    appsettings.json
    appsettings.{Environment}.json
    當應用程式執行在 Development 環境時使用 User secrets
    環境變數
    命令列引數
  • 新增以下日誌(logging)providers:
    控制檯
    除錯
    EventSource
    EventLog (只有執行在 Windows 系統時)
  • 當環境是 Development 時使能 scope validation 和 dependency validation

ConfigureWebHostDefaults 方法:

文章中下面的 Settings for all app types 和 Settings for web apps 部分展示瞭如果覆蓋預設 builder 設定。

Framework-provided services

下面的服務會自動註冊:

更多關於 framework-provided services 的資訊,檢視 Dependency injection in ASP.NET Core

IHostApplicationLifetime

注入  IHostApplicationLifetime (之前叫做 IApplicationLifetime) 服務到任一類中處理 post-startup 和 優雅關閉的任務。介面中的三個屬性是用來註冊應用程式啟動和停止時間處理方法的取消令牌。介面還包括一個 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 的預設實現。

ConsoleLifetime:

IHostEnvironment

注入服務 IHostEnvironment 到類中獲取關於下列設定的資訊:

Web 應用程式實現了 IWebHostEnvironment 介面,它繼承了 IHostEnvironment 並新增了 WebRootPath

Host 配置

Host 配置用於 IHostEnvironment 實現的屬性。

Host 配置使用 ConfigureAppConfiguration 中的 HostBuilderContext.Configuration。在 ConfigureAppConfiguration 之後,使用應用程式配置替換 HostBuilderContext.Configuration。

為了新增主機配置,呼叫介面 IHostBuilder 上的 ConfigureHostConfiguration 方法。ConfigureHostConfiguration 可以被多次呼叫生成累積的結果。主機使用在給定鍵值最後設定值的選項。

字首為 DOTNET_ 的環境變數和命令列引數包含在 CreateDefaultBuilder 中。對於 web 應用程式,字首為 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 配置

App 配置通過呼叫 IHostBuilder 介面的 ConfigureAppConfiguration 方法建立。ConfigureAppConfiguration 可以多次呼叫生成累積的結果。App 使用在給定鍵上最後一個設定值得選項。

建立配置的 ConfigureAppConfiguration 在 HostBuilderContext.Configuration 中,用於後續操作,它作為一個服務從依賴注入 (DI) 中獲取。主機配置也會被新增到 App 配置中。

更多資訊檢視 Configuration in ASP.NET Core

所有應用程式型別的配置

這部分列出的主機配置會被應用到 HTTP 和 non-HTTP 工作負載中。預設的用來配置這些設定的環境變數可以有一個 DOTNET_  或者 ASPNETCORE_ 的字首。更多資訊檢視 Default builder settings 部分。

 

ApplicationName

IHostEnvironment.ApplicationName 屬性在主機構造方法中通過 host 配置設定。

Key: applicationName

Type: string

Default: 包含應用程式入口點的程式集的名稱

Environment variable: <PREFIX_>APPLICATIONNAME

ContentRoot

IHostEnvironment.ContentRootPath 屬性決定主機從哪裡開始搜尋內容檔案。如果路徑不存在,主機啟動失敗。

Key: contentRoot

Type: string

Default: 應用程式程式集所在的目錄

Environment variable: <PREFIX_>CONTENTROOT

為了設定這個值,使用環境變數或者呼叫 IHostBuilder 介面的 UseContentRoot 方法:

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

更多資訊檢視:

EnvironmentName

IHostEnvironment.EnvironmentName 屬性可以被設定為任意值。框架本身定義的值包括 Development,Staging,和 Production。值不區分大小寫。

Key: environment

Type: string

Default: Production

Environment variable: <PREFIX_>ENVIRONMENT

使用 IHostBuilder 介面的 UseEnvironment 方法設定這個值:

Host.CreateDefaultBuilder(args)
    .UseEnvironment("Development")
    //...

ShutdownTimeout

HostOptions.ShutdownTimeout 為 StopAsync 設定超時時間。預設值是 5 秒。在超時時間內,主機會:

如果超時時間在所有託管服務停止之前過期了,任何任然活動的服務都會在應用程式關閉的時候停止。即使它們沒有完成處理,服務也會停止。如果服務需要更多的時間去停止,請增加超時時間。

Key: shutdownTimeoutSeconds

Type: int

Default: 5 second

Environment variable: <PREFIX_>SHUTDOWNTIMEOUTSECONDS

使用環境變數或者配置 HostOptions 設定這個值。下面的例子設定了超時時間為 20 秒:

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

禁用配置改變時重新載入應用程式配置

預設的,appsetting.json 和 appsetting.{Environment}.json 檔案改變時會被重新載入。在 ASP.NET Core 5.0 或者更新的版本中可以設定 hostBuilder:reloadConfigOnChange 鍵值為 false 來禁用重新載入的行為。

Key: hostBuilder:reloadCofigOnChange

Type: bool(true or 1)

Default: true

Command-line argument: hostBuilder:reloadConfigOnChange

Environment variable: <PREFIX_>hostBuilder:reloadConfigureOnChange

⚠️   警告

冒號 (:) 分隔符在所有平臺分層鍵值上的環境變數是不工作的。更多資訊檢視 Environment variables

Web 應用程式設定

一些主機設定會應用到 HTTP 工作負載中。預設的,用來配置這些設定的環境變數會有 DOTNET_  或者 ASPNETCORE_ 字首。

可以使用 IWebHostBuilder 的擴充套件方法設定這些配置。例如下面的示例,程式碼展示瞭如果呼叫擴充套件方法,假設webBuilder 是 IWebHostBuilder 的例項物件:

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

CaptureStartupErrors

當設定為 false 的時候,在啟動過程中出現的錯誤會導致主機退出。當設定為 true 的時候,主機會在啟動過程中捕獲異常並且試圖啟動伺服器。

Key: captureStartupErrors

Type: bool (true 或者 1)

Default: 預設是 false,除非應用程式使用 Kestrle 執行在 IIS 之後,這時預設值是 true

Environment variable: <PREFIX_>CAPTURESTARTUPERRORS

使用配置或者呼叫 CaptureStartupErros 設定該值:

webBuilder.CaptureStartupErrors(true);

DetailedErrors

當使能的時候,或者 environment 環境變數是 Development 的時候,應用程式會捕捉詳細錯誤資訊。

Key: detailedErrors

Type: bool (true 或者 1)

Default: false

Environment variable: <PREFIXE_>_DETAILEDERRORS

使用配置或者呼叫 UseSetting 設定該值:

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

HostingStartupAssemblies

是一個啟動時載入的託管的啟動程式集的以逗號分隔的字串。儘管預設配置值是一個空的字串,託管啟動程式集總是包含應用程式的程式集。當託管啟動程式集被提供,它們在應用程式啟動時建立公共服務的過程中會被新增到應用程式的程式集中載入。

Key: hostingStartupAssemblies

Type: string

Default: Empty string

Environment variable: <PREFIX_>_HOSTINGSTARTUPASSEMBLIES

使用配置或者呼叫 UseSetting 設定該值:

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

HostingStartupExcludeAssemblies

啟動時排除的託管啟動程式集,以逗號分隔的字串

Key: hostingStartupExcludeAssemblies

Type: string

Default: Empty string

Environment variable: <PREFIX_>_HOSTINGSTARTUPEXCLUDEASSEMBLIES

使用配置或者呼叫 UseSetting 設定該值:

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

HTTPS_Port

HTTPS 重定向埠。在 enforcing HTTPS 中使用。

Key: https_port

Type: string

Default: A default value isn't set

Environment variable: <PREFIX_>HTTPS_PORT

使用配置或者呼叫 UseSetting 設定該值:

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

PreferHostingUrls

標識主機是否應該監聽 IWebHostBuilder 配置的 URLs 而不是使用 IServer 的實現配置的 URLs。

Key: preferHostingUrls

Type: bool (true 或者 1)

Default: true

Environment varibale: <PREFIX_>PREFERHOSTINGURLS

使用環境變數或者呼叫 PreferHostingUrls 設定該值:

webBuilder.PreferHostingUrls(false);

PreventHostingStartup

阻止託管啟動程式集的自動載入,包含應用程式程式集配置的託管啟動程式集。更多資訊檢視 Use hosting startup assemblies in ASP.NET Core

Key: preventHostingStartup

Type:bool (true 或者 1)

Default: false

Environment variable: <PREFIX_>PREVENTHOSTINGSTARTUP

使用環境變數或者呼叫 UseSetting 設定這個值:

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

StartupAssembly

用來查詢 Startup 類的程式集。

Key: startupAssembly

Type: string

Default: 應用程式程式集

Environment variable: <PREFIX_>STARTUPASSEMBLY

使用環境變數或者呼叫 UseStartup 設定這個值。UseStartup 可以接收一個程式集的名稱(string)或者一個型別 (TStartup)。如果多個 UseStartup 方法被呼叫,最後一個優先順序最高:

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

URLs

一組逗號分隔的帶有埠和協議的 IP 地址或者主機地址,伺服器應該在這些地址上監聽請求。例如,http://localhost:123。使用 "*" 來表明伺服器應該在使用特定埠和協議(例如,http://*:5000)的任意 IP 地址或者主機名稱上監聽。協議(http:// 或者 https://)必須包含在每一個 URL 中。支援的格式因伺服器而異。

Key: urls

Type: string

Default: http://localhost:5000 和 https://localhost:5001

Environment variable: <PREFIX_>URLS

使用環境變數或者呼叫 UseUrls 設定這個值:

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

Kestrel 有它自己的 enpoint 配置 API。更多資訊檢視 Configure endpoints for the ASP.NET Core Kestrel web server

WebRoot

IWebHostEnvironment.WebRootPath 屬性決定了應用程式靜態資源的相對路徑。如果路徑不存在,一個 no-op 的檔案被使用。

Key: webroot

Type: string

Default: 預設是 wwwroot。路徑{content root}/wwwroot 必須存在

Environment variable: <PREFIX_>WEBROOT

使用環境變數或者 IWebHostBuilder 介面的 UseWebRoot 方法設定這個值:

webBuilder.UseWebRoot("public");

更多資訊檢視:

管理主機生命週期

呼叫 IHost 的實現方法啟動和停止應用程式。這些方法會影響所有註冊在服務容器中的 IHostedService 的實現。

Run

Run 執行應用程式,阻塞呼叫執行緒直到主機關閉。

RunAsync

RunAsync 執行應用程式,當一個取消令牌或者關閉被觸發的時候返回一個完成 Task

RunConsoleAsync

RunConsoleAsync 使能控制檯支援,建立,啟動主機,等待 Ctrl + C / SIGINT 或者 SIGTERM 關閉。

Start

Start 以同步方式啟動主機

StartAsync

StartAsync 啟動主機,當取消令牌或者關閉被觸發了,會返回一個完成的 Task

WaitForStartAsync 在 StartAsync 的開始會被呼叫,繼續執行之前會一直等待它完成。這可以用來延遲啟動,直到接收到外部事件的通知。

StopAsync

StopAsync 嘗試使用提供的超時時間停止主機

WaitForShutdown

WaitForShutdown 阻塞呼叫執行緒直到生命週期 IHostLifttime 的關閉被觸發,例如通過 Ctrl + C / SIGINT  或者 SIGTERM。

WaitForShutdownAsync

WaitForShutdownAsync 在通過給定的令牌或者呼叫 StopAsync 觸發關閉的時候回返回一個完成的 Task

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

相關文章