.NET 通用主機(jī)

2019-04-17 08:58 更新

ASP.NET Core 應(yīng)用配置和啟動(dòng)主機(jī)。 主機(jī)負(fù)責(zé)應(yīng)用程序啟動(dòng)和生存期管理。

本文介紹 ASP.NET Core 泛型主機(jī) (HostBuilder),該主機(jī)用于無(wú)法處理 HTTP 請(qǐng)求的應(yīng)用。

泛型主機(jī)的用途是將 HTTP 管道從 Web 主機(jī) API 中分離出來(lái),從而啟用更多的主機(jī)方案。 基于泛型主機(jī)的消息、后臺(tái)任務(wù)和其他非 HTTP 工作負(fù)載可從橫切功能(如配置、依賴關(guān)系注入 [DI] 和日志記錄)中受益。

泛型主機(jī)是 ASP.NET Core 2.1 中的新增功能,不適用于 Web 承載方案。 對(duì)于 Web 承載方案,請(qǐng)使用 Web 主機(jī)。 泛型主機(jī)將在未來(lái)版本中替換 Web 主機(jī),并在 HTTP 和非 HTTP 方案中充當(dāng)主要的主機(jī) API。

查看或下載示例代碼如何下載

在 Visual Studio Code 中運(yùn)行示例應(yīng)用時(shí),請(qǐng)使用外部或集成終端。 請(qǐng)勿在 internalConsole 中運(yùn)行示例。

在 Visual Studio Code 中設(shè)置控制臺(tái):

  1. 打開(kāi) .vscode/launch.json 文件。
  2. 在 .NET Core 啟動(dòng)(控制臺(tái))配置中,找到控制臺(tái)條目。 將值設(shè)置為 externalTerminal 或 integratedTerminal。

介紹

通用主機(jī)庫(kù)位于 Microsoft.Extensions.Hosting 命名空間中,由 Microsoft.Extensions.Hosting 包提供。 Microsoft.AspNetCore.App 元包(ASP.NET Core 2.1 或更高版本)中包括 Microsoft.Extensions.Hosting 包。

IHostedService 是執(zhí)行代碼的入口點(diǎn)。 每個(gè) IHostedService 實(shí)現(xiàn)都按照 ConfigureServices 中服務(wù)注冊(cè)的順序執(zhí)行。 主機(jī)啟動(dòng)時(shí),每個(gè) IHostedService 上都會(huì)調(diào)用 StartAsync,主機(jī)正常關(guān)閉時(shí),以反向注冊(cè)順序調(diào)用 StopAsync。

設(shè)置主機(jī)

IHostBuilder 是供庫(kù)和應(yīng)用初始化、生成和運(yùn)行主機(jī)的主要組件:

C#

public static async Task Main(string[] args)
{
    var host = new HostBuilder()
        .Build();

    await host.RunAsync();
}

選項(xiàng)

HostOptions 配置 IHost 的選項(xiàng)。

關(guān)閉超時(shí)值

ShutdownTimeout 設(shè)置 StopAsync 的超時(shí)值。 默認(rèn)值為 5 秒。

Program.Main 中的以下選項(xiàng)配置將默認(rèn)值為 5 秒的關(guān)閉超時(shí)值增加至 20 秒:

C#

var host = new HostBuilder()
    .ConfigureServices((hostContext, services) =>
    {
        services.Configure<HostOptions>(option =>
        {
            option.ShutdownTimeout = System.TimeSpan.FromSeconds(20);
        });
    })
    .Build();

默認(rèn)服務(wù)

在主機(jī)初始化期間注冊(cè)以下服務(wù):

主機(jī)配置

主機(jī)配置的創(chuàng)建方式如下:

擴(kuò)展方法

應(yīng)用程序鍵(名稱)

IHostingEnvironment.ApplicationName 屬性是在主機(jī)構(gòu)造期間通過(guò)主機(jī)配置設(shè)定的。 要顯式設(shè)置值,請(qǐng)使用 HostDefaults.ApplicationKey

密鑰:applicationName類型:string默認(rèn)值:包含應(yīng)用入口點(diǎn)的程序集的名稱。設(shè)置使用:HostBuilderContext.HostingEnvironment.ApplicationName環(huán)境變量:<PREFIX_>APPLICATIONNAME(<PREFIX_> 是用戶定義的可選前綴

內(nèi)容根

此設(shè)置確定主機(jī)從哪里開(kāi)始搜索內(nèi)容文件。

鍵:contentRoot類型:string默認(rèn)值:默認(rèn)為應(yīng)用程序集所在的文件夾。設(shè)置使用:UseContentRoot環(huán)境變量:<PREFIX_>CONTENTROOT(<PREFIX_> 是用戶定義的可選前綴

如果路徑不存在,主機(jī)將無(wú)法啟動(dòng)。

C#

var host = new HostBuilder()
    .UseContentRoot("c:\\<content-root>")

環(huán)境

設(shè)置應(yīng)用的環(huán)境。

鍵:環(huán)境類型:string默認(rèn)值:生產(chǎn)設(shè)置使用:UseEnvironment環(huán)境變量:<PREFIX_>ENVIRONMENT(<PREFIX_> 是用戶定義的可選前綴

環(huán)境可以設(shè)置為任何值。 框架定義的值包括 Development``Staging 和 Production。 值不區(qū)分大小寫。

C#

var host = new HostBuilder()
    .UseEnvironment(EnvironmentName.Development)

ConfigureHostConfiguration

ConfigureHostConfiguration 使用 IConfigurationBuilder 來(lái)為主機(jī)創(chuàng)建 IConfiguration。 主機(jī)配置用于初始化 IHostingEnvironment,以供在應(yīng)用的構(gòu)建過(guò)程中使用。

可多次調(diào)用 ConfigureHostConfiguration,并得到累計(jì)結(jié)果。 主機(jī)使用上一次在一個(gè)給定鍵上設(shè)置值的選項(xiàng)。

主機(jī)配置自動(dòng)流向應(yīng)用配置(ConfigureAppConfiguration 和應(yīng)用的其余部分)。

默認(rèn)情況下不包括提供程序。 必須在 ConfigureHostConfiguration 中顯式指定應(yīng)用所需的任何配置提供程序,包括:

  • 文件配置(例如,來(lái)自 hostsettings.json 文件)。
  • 環(huán)境變量配置。
  • 命令行參數(shù)配置。
  • 任何其他所需的配置提供程序。

通過(guò)使用 SetBasePath 指定應(yīng)用的基本路徑,然后調(diào)用其中一個(gè)文件配置提供程序,可以啟用主機(jī)的文件配置。 示例應(yīng)用使用 JSON 文件 hostsettings.json,并調(diào)用 AddJsonFile 來(lái)使用文件的主機(jī)配置設(shè)置。

要添加主機(jī)的環(huán)境變量配置,請(qǐng)?jiān)谥鳈C(jī)生成器上調(diào)用 AddEnvironmentVariables。 AddEnvironmentVariables 接受用戶定義的前綴(可選)。 示例應(yīng)用使用前綴 PREFIX_。 當(dāng)系統(tǒng)讀取環(huán)境變量時(shí),便會(huì)刪除前綴。 配置示例應(yīng)用的主機(jī)后,PREFIX_ENVIRONMENT 的環(huán)境變量值就變成 environment 密鑰的主機(jī)配置值。

在開(kāi)發(fā)過(guò)程中,如果使用 Visual Studio 或通過(guò) dotnet run 運(yùn)行應(yīng)用,可能會(huì)在 Properties/launchSettings.json 文件中設(shè)置環(huán)境變量。 若在開(kāi)發(fā)過(guò)程中使用 Visual Studio Code,可能會(huì)在 .vscode/launch.json 文件中設(shè)置環(huán)境變量。 有關(guān)更多信息,請(qǐng)參見(jiàn)在 ASP.NET Core 中使用多個(gè)環(huán)境

通過(guò)調(diào)用 AddCommandLine 可添加命令行配置。 最后添加命令行配置以允許命令行參數(shù)替代之前配置提供程序提供的配置。

hostsettings.json:

C#

{
  "environment": "Development"
}

可以通過(guò) applicationName 和 contentRoot 鍵提供其他配置。

示例 HostBuilder 配置使用 ConfigureHostConfiguration

C#

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

ConfigureAppConfiguration

通過(guò)在 IHostBuilder 實(shí)現(xiàn)上調(diào)用 ConfigureAppConfiguration 創(chuàng)建應(yīng)用配置。ConfigureAppConfiguration 使用 IConfigurationBuilder 來(lái)為應(yīng)用創(chuàng)建 IConfiguration。 可多次調(diào)用 ConfigureAppConfiguration,并得到累計(jì)結(jié)果。 應(yīng)用使用上一次在一個(gè)給定鍵上設(shè)置值的選項(xiàng)。HostBuilderContext.Configuration 中提供 ConfigureAppConfiguration 創(chuàng)建的配置,以供進(jìn)行后續(xù)操作和在 Services 中使用。

應(yīng)用配置會(huì)自動(dòng)接收 ConfigureHostConfiguration 提供的主機(jī)配置。

示例應(yīng)用配置使用 ConfigureAppConfiguration

C#

var host = new HostBuilder()
    .ConfigureAppConfiguration((hostContext, configApp) =>
    {
        configApp.SetBasePath(Directory.GetCurrentDirectory());
        configApp.AddJsonFile("appsettings.json", optional: true);
        configApp.AddJsonFile(
            $"appsettings.{hostContext.HostingEnvironment.EnvironmentName}.json", 
            optional: true);
        configApp.AddEnvironmentVariables(prefix: "PREFIX_");
        configApp.AddCommandLine(args);
    })

appsettings.json:

C#

{
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "AllowedHosts": "*"
}

appsettings.Development.json:

C#

{
  "Logging": {
    "LogLevel": {
      "Default": "Debug",
      "System": "Information",
      "Microsoft": "Information"
    }
  }
}

appsettings.Production.json:

C#

{
  "Logging": {
    "LogLevel": {
      "Default": "Error",
      "System": "Information",
      "Microsoft": "Information"
    }
  }
}

要將設(shè)置文件移動(dòng)到輸出目錄,請(qǐng)?jiān)陧?xiàng)目文件中將設(shè)置文件指定為 MSBuild 項(xiàng)目項(xiàng)。 示例應(yīng)用移動(dòng)具有以下 <Content> 項(xiàng)的 JSON 應(yīng)用設(shè)置文件和 hostsettings.json:

XML

<ItemGroup>
  <Content Include="**\*.json" Exclude="bin\**\*;obj\**\*" 
      CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>

ConfigureServices

ConfigureServices 將服務(wù)添加到應(yīng)用的依賴關(guān)系注入容器。 可多次調(diào)用 ConfigureServices,并得到累計(jì)結(jié)果。

托管服務(wù)是一個(gè)類,具有實(shí)現(xiàn) IHostedService 接口的后臺(tái)任務(wù)邏輯。 有關(guān)更多信息,請(qǐng)參見(jiàn)在 ASP.NET Core 中使用托管服務(wù)實(shí)現(xiàn)后臺(tái)任務(wù)

示例應(yīng)用使用 AddHostedService 擴(kuò)展方法向應(yīng)用添加生存期事件 LifetimeEventsHostedService 和定時(shí)后臺(tái)任務(wù) TimedHostedService 服務(wù):

C#

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

ConfigureLogging

ConfigureLogging 添加了一個(gè)委托來(lái)配置提供的 ILoggingBuilder。 可以利用相加結(jié)果多次調(diào)用 ConfigureLogging。

C#

var host = new HostBuilder()
    .ConfigureLogging((hostContext, configLogging) =>
    {
        configLogging.AddConsole();
        configLogging.AddDebug();
    })

UseConsoleLifetime

UseConsoleLifetime 偵聽(tīng) Ctrl+C/SIGINT 或 SIGTERM 并調(diào)用 StopApplication 來(lái)啟動(dòng)關(guān)閉進(jìn)程。UseConsoleLifetime 解除阻止 RunAsync 和 WaitForShutdownAsync 等擴(kuò)展。 ConsoleLifetime 預(yù)注冊(cè)為默認(rèn)生存期實(shí)現(xiàn)。 使用注冊(cè)的最后一個(gè)生存期。

C#

var host = new HostBuilder()
    .UseConsoleLifetime()

容器配置

為支持插入其他容器中,主機(jī)可以接受 IServiceProviderFactory<TContainerBuilder>。 提供工廠不屬于 DI 容器注冊(cè),而是用于創(chuàng)建具體 DI 容器的主機(jī)內(nèi)部函數(shù)。UseServiceProviderFactory(IServiceProviderFactory<TContainerBuilder>) 重寫用于創(chuàng)建應(yīng)用的服務(wù)提供程序的默認(rèn)工廠。

ConfigureContainer 方法托管自定義容器配置。 ConfigureContainer 提供在基礎(chǔ)主機(jī) API 的基礎(chǔ)之上配置容器的強(qiáng)類型體驗(yàn)。 可以利用相加結(jié)果多次調(diào)用 ConfigureContainer。

為應(yīng)用創(chuàng)建服務(wù)容器:

C#

namespace GenericHostSample
{
    internal class ServiceContainer
    {
    }
}

提供服務(wù)容器工廠:

C#

using System;
using Microsoft.Extensions.DependencyInjection;

namespace GenericHostSample
{
    internal class ServiceContainerFactory : 
        IServiceProviderFactory<ServiceContainer>
    {
        public ServiceContainer CreateBuilder(
            IServiceCollection services)
        {
            return new ServiceContainer();
        }

        public IServiceProvider CreateServiceProvider(
            ServiceContainer containerBuilder)
        {
            throw new NotImplementedException();
        }
    }
}

使用該工廠并為應(yīng)用配置自定義服務(wù)容器:

C#

var host = new HostBuilder()
    .UseServiceProviderFactory<ServiceContainer>(new ServiceContainerFactory())
    .ConfigureContainer<ServiceContainer>((hostContext, container) =>
    {
    })

擴(kuò)展性

在 IHostBuilder 上使用擴(kuò)展方法實(shí)現(xiàn)主機(jī)擴(kuò)展性。 以下示例介紹擴(kuò)展方法如何使用 在 ASP.NET Core 中使用托管服務(wù)實(shí)現(xiàn)后臺(tái)任務(wù) 中所示的 TimedHostedService 示例來(lái)擴(kuò)展 IHostBuilder 實(shí)現(xiàn)。

C#

var host = new HostBuilder()
    .UseHostedService<TimedHostedService>()
    .Build();

await host.StartAsync();

應(yīng)用建立 UseHostedService 擴(kuò)展方法,以注冊(cè)在 T 中傳遞的托管服務(wù):

C#

using System;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

public static class Extensions
{
    public static IHostBuilder UseHostedService<T>(this IHostBuilder hostBuilder)
        where T : class, IHostedService, IDisposable
    {
        return hostBuilder.ConfigureServices(services =>
            services.AddHostedService<T>());
    }
}

管理主機(jī)

IHost 實(shí)現(xiàn)負(fù)責(zé)啟動(dòng)和停止服務(wù)容器中注冊(cè)的 IHostedService 實(shí)現(xiàn)。

運(yùn)行

Run 運(yùn)行應(yīng)用并阻止調(diào)用線程,直到關(guān)閉主機(jī):

C#

public class Program
{
    public void Main(string[] args)
    {
        var host = new HostBuilder()
            .Build();

        host.Run();
    }
}

RunAsync

RunAsync 運(yùn)行應(yīng)用并返回在觸發(fā)取消令牌或關(guān)閉時(shí)完成的 Task

C#

public class Program
{
    public static async Task Main(string[] args)
    {
        var host = new HostBuilder()
            .Build();

        await host.RunAsync();
    }
}

RunConsoleAsync

RunConsoleAsync 啟用控制臺(tái)支持、生成和啟動(dòng)主機(jī),以及等待 Ctrl+C/SIGINT 或 SIGTERM 關(guān)閉。

C#

public class Program
{
    public static async Task Main(string[] args)
    {
        var hostBuilder = new HostBuilder();

        await hostBuilder.RunConsoleAsync();
    }
}

Start 和 StopAsync

Start 同步啟動(dòng)主機(jī)。

StopAsync 嘗試在提供的超時(shí)時(shí)間內(nèi)停止主機(jī)。

C#

public class Program
{
    public static async Task Main(string[] args)
    {
        var host = new HostBuilder()
            .Build();

        using (host)
        {
            host.Start();

            await host.StopAsync(TimeSpan.FromSeconds(5));
        }
    }
}

StartAsync 和 StopAsync

StartAsync 啟動(dòng)應(yīng)用。

StopAsync 停止應(yīng)用。

C#

public class Program
{
    public static async Task Main(string[] args)
    {
        var host = new HostBuilder()
            .Build();

        using (host)
        {
            await host.StartAsync();

            await host.StopAsync();
        }
    }
}

WaitForShutdown

WaitForShutdown 通過(guò) IHostLifetime 觸發(fā),例如 ConsoleLifetime(偵聽(tīng) Ctrl+C/SIGINT 或 SIGTERM)。 WaitForShutdown 調(diào)用 StopAsync

C#

public class Program
{
    public void Main(string[] args)
    {
        var host = new HostBuilder()
            .Build();

        using (host)
        {
            host.Start();

            host.WaitForShutdown();
        }
    }
}

WaitForShutdownAsync

WaitForShutdownAsync 返回在通過(guò)給定的令牌和調(diào)用 StopAsync 來(lái)觸發(fā)關(guān)閉時(shí)完成的 Task。

C#

public class Program
{
    public static async Task Main(string[] args)
    {
        var host = new HostBuilder()
            .Build();

        using (host)
        {
            await host.StartAsync();

            await host.WaitForShutdownAsync();
        }

    }
}

外部控件

使用可從外部調(diào)用的方法,能夠?qū)崿F(xiàn)主機(jī)的外部控件:

C#

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

在 StartAsync 開(kāi)始時(shí)調(diào)用 WaitForStartAsync,在繼續(xù)之前,會(huì)一直等待該操作完成。 它可用于延遲啟動(dòng),直到外部事件發(fā)出信號(hào)。

IHostingEnvironment 接口

IHostingEnvironment 提供有關(guān)應(yīng)用托管環(huán)境的信息。 使用構(gòu)造函數(shù)注入獲取 IHostingEnvironment以使用其屬性和擴(kuò)展方法:

C#

public class MyClass
{
    private readonly IHostingEnvironment _env;

    public MyClass(IHostingEnvironment env)
    {
        _env = env;
    }

    public void DoSomething()
    {
        var environmentName = _env.EnvironmentName;
    }
}

有關(guān)更多信息,請(qǐng)參見(jiàn)在 ASP.NET Core 中使用多個(gè)環(huán)境。

IApplicationLifetime 接口

IApplicationLifetime 允許啟動(dòng)后和關(guān)閉活動(dòng),包括正常關(guān)閉請(qǐng)求。 接口上的三個(gè)屬性是用于注冊(cè) Action 方法(用于定義啟動(dòng)和關(guān)閉事件)的取消標(biāo)記。

取消標(biāo)記觸發(fā)條件
ApplicationStarted主機(jī)已完全啟動(dòng)。
ApplicationStopped主機(jī)正在完成正常關(guān)閉。 應(yīng)處理所有請(qǐng)求。 關(guān)閉受到阻止,直到完成此事件。
ApplicationStopping主機(jī)正在執(zhí)行正常關(guān)閉。 仍在處理請(qǐng)求。 關(guān)閉受到阻止,直到完成此事件。

構(gòu)造函數(shù)將 IApplicationLifetime 服務(wù)注入到任何類中。 示例應(yīng)用將構(gòu)造函數(shù)注入到 LifetimeEventsHostedService 類(一個(gè) IHostedService 實(shí)現(xiàn))中,用于注冊(cè)事件。

LifetimeEventsHostedService.cs:

C#

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

StopApplication 請(qǐng)求終止應(yīng)用。 以下類在調(diào)用類的 Shutdown 方法時(shí)使用 StopApplication 正常關(guān)閉應(yīng)用:

C#

public class MyClass
{
    private readonly IApplicationLifetime _appLifetime;

    public MyClass(IApplicationLifetime appLifetime)
    {
        _appLifetime = appLifetime;
    }

    public void Shutdown()
    {
        _appLifetime.StopApplication();
    }
}


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)