.NET 通用主机

2019-04-17 08:58 更新

ASP.NET Core 应用配置和启动主机。 主机负责应用程序启动和生存期管理。

本文介绍 ASP.NET Core 泛型主机 (HostBuilder),该主机用于无法处理 HTTP 请求的应用。

泛型主机的用途是将 HTTP 管道从 Web 主机 API 中分离出来,从而启用更多的主机方案。 基于泛型主机的消息、后台任务和其他非 HTTP 工作负载可从横切功能(如配置、依赖关系注入 [DI] 和日志记录)中受益。

泛型主机是 ASP.NET Core 2.1 中的新增功能,不适用于 Web 承载方案。 对于 Web 承载方案,请使用 Web 主机。 泛型主机将在未来版本中替换 Web 主机,并在 HTTP 和非 HTTP 方案中充当主要的主机 API。

查看或下载示例代码如何下载

在 Visual Studio Code 中运行示例应用时,请使用外部或集成终端。 请勿在 internalConsole 中运行示例。

在 Visual Studio Code 中设置控制台:

  1. 打开 .vscode/launch.json 文件。
  2. 在 .NET Core 启动(控制台)配置中,找到控制台条目。 将值设置为 externalTerminal 或 integratedTerminal。

介绍

通用主机库位于 Microsoft.Extensions.Hosting 命名空间中,由 Microsoft.Extensions.Hosting 包提供。 Microsoft.AspNetCore.App 元包(ASP.NET Core 2.1 或更高版本)中包括 Microsoft.Extensions.Hosting 包。

IHostedService 是执行代码的入口点。 每个 IHostedService 实现都按照 ConfigureServices 中服务注册的顺序执行。 主机启动时,每个 IHostedService 上都会调用 StartAsync,主机正常关闭时,以反向注册顺序调用 StopAsync

设置主机

IHostBuilder 是供库和应用初始化、生成和运行主机的主要组件:

C#

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

    await host.RunAsync();
}

选项

HostOptions 配置 IHost 的选项。

关闭超时值

ShutdownTimeout 设置 StopAsync 的超时值。 默认值为 5 秒。

Program.Main 中的以下选项配置将默认值为 5 秒的关闭超时值增加至 20 秒:

C#

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

默认服务

在主机初始化期间注册以下服务:

主机配置

主机配置的创建方式如下:

扩展方法

应用程序键(名称)

IHostingEnvironment.ApplicationName 属性是在主机构造期间通过主机配置设定的。 要显式设置值,请使用 HostDefaults.ApplicationKey

密钥:applicationName类型:string默认值:包含应用入口点的程序集的名称。设置使用:HostBuilderContext.HostingEnvironment.ApplicationName环境变量:<PREFIX_>APPLICATIONNAME(<PREFIX_> 是用户定义的可选前缀

内容根

此设置确定主机从哪里开始搜索内容文件。

键:contentRoot类型:string默认值:默认为应用程序集所在的文件夹。设置使用:UseContentRoot环境变量:<PREFIX_>CONTENTROOT(<PREFIX_> 是用户定义的可选前缀

如果路径不存在,主机将无法启动。

C#

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

环境

设置应用的环境

键:环境类型:string默认值:生产设置使用:UseEnvironment环境变量:<PREFIX_>ENVIRONMENT(<PREFIX_> 是用户定义的可选前缀

环境可以设置为任何值。 框架定义的值包括 Development``Staging 和 Production。 值不区分大小写。

C#

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

ConfigureHostConfiguration

ConfigureHostConfiguration 使用 IConfigurationBuilder 来为主机创建 IConfiguration。 主机配置用于初始化 IHostingEnvironment,以供在应用的构建过程中使用。

可多次调用 ConfigureHostConfiguration,并得到累计结果。 主机使用上一次在一个给定键上设置值的选项。

主机配置自动流向应用配置(ConfigureAppConfiguration 和应用的其余部分)。

默认情况下不包括提供程序。 必须在 ConfigureHostConfiguration 中显式指定应用所需的任何配置提供程序,包括:

  • 文件配置(例如,来自 hostsettings.json 文件)。
  • 环境变量配置。
  • 命令行参数配置。
  • 任何其他所需的配置提供程序。

通过使用 SetBasePath 指定应用的基本路径,然后调用其中一个文件配置提供程序,可以启用主机的文件配置。 示例应用使用 JSON 文件 hostsettings.json,并调用 AddJsonFile 来使用文件的主机配置设置。

要添加主机的环境变量配置,请在主机生成器上调用 AddEnvironmentVariables。 AddEnvironmentVariables 接受用户定义的前缀(可选)。 示例应用使用前缀 PREFIX_。 当系统读取环境变量时,便会删除前缀。 配置示例应用的主机后,PREFIX_ENVIRONMENT 的环境变量值就变成 environment 密钥的主机配置值。

在开发过程中,如果使用 Visual Studio 或通过 dotnet run 运行应用,可能会在 Properties/launchSettings.json 文件中设置环境变量。 若在开发过程中使用 Visual Studio Code,可能会在 .vscode/launch.json 文件中设置环境变量。 有关更多信息,请参见在 ASP.NET Core 中使用多个环境

通过调用 AddCommandLine 可添加命令行配置。 最后添加命令行配置以允许命令行参数替代之前配置提供程序提供的配置。

hostsettings.json:

C#

{
  "environment": "Development"
}

可以通过 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

通过在 IHostBuilder 实现上调用 ConfigureAppConfiguration 创建应用配置。ConfigureAppConfiguration 使用 IConfigurationBuilder 来为应用创建 IConfiguration。 可多次调用 ConfigureAppConfiguration,并得到累计结果。 应用使用上一次在一个给定键上设置值的选项。HostBuilderContext.Configuration 中提供 ConfigureAppConfiguration 创建的配置,以供进行后续操作和在 Services 中使用。

应用配置会自动接收 ConfigureHostConfiguration 提供的主机配置。

示例应用配置使用 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"
    }
  }
}

要将设置文件移动到输出目录,请在项目文件中将设置文件指定为 MSBuild 项目项。 示例应用移动具有以下 <Content> 项的 JSON 应用设置文件和 hostsettings.json:

XML

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

ConfigureServices

ConfigureServices 将服务添加到应用的依赖关系注入容器。 可多次调用 ConfigureServices,并得到累计结果。

托管服务是一个类,具有实现 IHostedService 接口的后台任务逻辑。 有关更多信息,请参见在 ASP.NET Core 中使用托管服务实现后台任务

示例应用使用 AddHostedService 扩展方法向应用添加生存期事件 LifetimeEventsHostedService 和定时后台任务 TimedHostedService 服务:

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 添加了一个委托来配置提供的 ILoggingBuilder。 可以利用相加结果多次调用 ConfigureLogging

C#

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

UseConsoleLifetime

UseConsoleLifetime 侦听 Ctrl+C/SIGINT 或 SIGTERM 并调用 StopApplication 来启动关闭进程。UseConsoleLifetime 解除阻止 RunAsync 和 WaitForShutdownAsync 等扩展。 ConsoleLifetime 预注册为默认生存期实现。 使用注册的最后一个生存期。

C#

var host = new HostBuilder()
    .UseConsoleLifetime()

容器配置

为支持插入其他容器中,主机可以接受 IServiceProviderFactory<TContainerBuilder>。 提供工厂不属于 DI 容器注册,而是用于创建具体 DI 容器的主机内部函数。UseServiceProviderFactory(IServiceProviderFactory<TContainerBuilder>) 重写用于创建应用的服务提供程序的默认工厂。

ConfigureContainer 方法托管自定义容器配置。 ConfigureContainer 提供在基础主机 API 的基础之上配置容器的强类型体验。 可以利用相加结果多次调用 ConfigureContainer

为应用创建服务容器:

C#

namespace GenericHostSample
{
    internal class ServiceContainer
    {
    }
}

提供服务容器工厂:

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

使用该工厂并为应用配置自定义服务容器:

C#

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

扩展性

在 IHostBuilder 上使用扩展方法实现主机扩展性。 以下示例介绍扩展方法如何使用 在 ASP.NET Core 中使用托管服务实现后台任务 中所示的 TimedHostedService 示例来扩展 IHostBuilder 实现。

C#

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

await host.StartAsync();

应用建立 UseHostedService 扩展方法,以注册在 T 中传递的托管服务:

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

管理主机

IHost 实现负责启动和停止服务容器中注册的 IHostedService 实现。

运行

Run 运行应用并阻止调用线程,直到关闭主机:

C#

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

        host.Run();
    }
}

RunAsync

RunAsync 运行应用并返回在触发取消令牌或关闭时完成的 Task

C#

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

        await host.RunAsync();
    }
}

RunConsoleAsync

RunConsoleAsync 启用控制台支持、生成和启动主机,以及等待 Ctrl+C/SIGINT 或 SIGTERM 关闭。

C#

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

        await hostBuilder.RunConsoleAsync();
    }
}

Start 和 StopAsync

Start 同步启动主机。

StopAsync 尝试在提供的超时时间内停止主机。

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 启动应用。

StopAsync 停止应用。

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 通过 IHostLifetime 触发,例如 ConsoleLifetime(侦听 Ctrl+C/SIGINT 或 SIGTERM)。 WaitForShutdown 调用 StopAsync

C#

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

        using (host)
        {
            host.Start();

            host.WaitForShutdown();
        }
    }
}

WaitForShutdownAsync

WaitForShutdownAsync 返回在通过给定的令牌和调用 StopAsync 来触发关闭时完成的 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();
        }

    }
}

外部控件

使用可从外部调用的方法,能够实现主机的外部控件:

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 开始时调用 WaitForStartAsync,在继续之前,会一直等待该操作完成。 它可用于延迟启动,直到外部事件发出信号。

IHostingEnvironment 接口

IHostingEnvironment 提供有关应用托管环境的信息。 使用构造函数注入获取 IHostingEnvironment以使用其属性和扩展方法:

C#

public class MyClass
{
    private readonly IHostingEnvironment _env;

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

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

有关更多信息,请参见在 ASP.NET Core 中使用多个环境

IApplicationLifetime 接口

IApplicationLifetime 允许启动后和关闭活动,包括正常关闭请求。 接口上的三个属性是用于注册 Action 方法(用于定义启动和关闭事件)的取消标记。

取消标记触发条件
ApplicationStarted主机已完全启动。
ApplicationStopped主机正在完成正常关闭。 应处理所有请求。 关闭受到阻止,直到完成此事件。
ApplicationStopping主机正在执行正常关闭。 仍在处理请求。 关闭受到阻止,直到完成此事件。

构造函数将 IApplicationLifetime 服务注入到任何类中。 示例应用将构造函数注入到 LifetimeEventsHostedService 类(一个 IHostedService 实现)中,用于注册事件。

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 请求终止应用。 以下类在调用类的 Shutdown 方法时使用 StopApplication 正常关闭应用:

C#

public class MyClass
{
    private readonly IApplicationLifetime _appLifetime;

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

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


以上内容是否对您有帮助:
在线笔记
App下载
App下载

扫描二维码

下载编程狮App

公众号
微信公众号

编程狮公众号