- 语言运行时
- 标准库
- JIT编译
- 编译器
【免费下载链接】runtime
.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
导读
Microsoft.Extensions.Hosting.Abstractions是 .NET 运行时仓库中托管体系(Hosting)的抽象层核心,它定义了"如何在一个应用中托管用户代码"的统一模式:通过宿主(Host)把配置(Configuration)、日志(Logging)、依赖注入(DI)串联起来,并以**托管服务(Hosted Service)**为原语让 ASP.NET Core 等应用模型与宿主对接。本文以 src/libraries/Microsoft.Extensions.Hosting.Abstractions/README.md 为骨架,结合该目录下的全部接口、基类与单元测试源码,系统讲解IHost/IHostBuilder抽象、IHostedService/BackgroundService托管服务模型、生命周期与运行辅助方法,并给出可复制的实战代码与源码级佐证。
一、什么是 Hosting Abstractions:托管抽象的价值
该包的核心定位在文档中一句话即可概括:"包含一个核心托管抽象,提供使用扩展库在应用中托管用户代码的模式"。它本身不提供具体实现(实现位于Microsoft.Extensions.Hosting包),而是定义了一套稳定的接口契约,让上层应用模型可以基于同一套抽象工作。
从文档与源码(PACKAGE.md)看,这套抽象封装了一个应用所需的资源与生命周期能力:
- 依赖注入(DI):宿主持有
IServiceProvider,托管服务与业务服务统一注册、统一解析; - 日志(Logging):宿主整合日志提供程序;
- 配置(Configuration):宿主构建分层的配置体系;
- 启动、停止与通知(Starting, stopping and obtaining notifications):通过生命周期令牌向应用广播启动/停止事件。
它最重要的作用是"接线(wire up)":ASP.NET Core 这类构建在托管之上的应用模型,正是通过托管服务原语与宿主集成的。同时,通用托管(Generic Host)也为三类场景提供了良好的集成支持:长运行控制台应用(long-running console applications)、Windows 服务、ASP.NET Core。
二、核心抽象一:IHost 与 IHostBuilder
1. IHost —— 程序(Program)抽象
IHost.cs 定义了"一个正在运行的程序":
public interface IHost : IDisposable { IServiceProvider Services { get; } Task StartAsync(CancellationToken cancellationToken = default); Task StopAsync(CancellationToken cancellationToken = default); }Services:暴露为程序配置好的服务容器,可通过它解析任意已注册服务;StartAsync:启动程序中配置的所有IHostedService对象,应用将持续运行直到被中断或调用IHostApplicationLifetime.StopApplication();StopAsync:尝试优雅停止程序,传入的CancellationToken表示"停止过程不再需要优雅"。
2. IHostBuilder —— 程序初始化抽象
IHostBuilder.cs 定义了宿主的构建阶段契约,所有方法均可链式调用,且多次调用结果可叠加(additive):
| 成员 | 作用 |
|---|---|
Properties | 构建过程中各组件共享状态的中心位置(IDictionary<object, object>) |
ConfigureHostConfiguration(Action<IConfigurationBuilder>) | 配置"构建器自身"的配置源,用于初始化后续构建使用的IHostEnvironment |
ConfigureAppConfiguration(Action<HostBuilderContext, IConfigurationBuilder>) | 配置"应用本身"的配置,结果在HostBuilderContext.Configuration与IHost.Services中均可获取 |
ConfigureServices(Action<HostBuilderContext, IServiceCollection>) | 向容器注册服务,可多次调用、结果叠加 |
UseServiceProviderFactory<TContainerBuilder>(...) | 替换创建服务提供程序的工厂,支持传入实例或Func<HostBuilderContext, ...>上下文工厂 |
ConfigureContainer<TContainerBuilder>(...) | 配置实例化后的第三方 DI 容器(如 Autofac),结果叠加 |
Build() | 执行初始化动作,仅能调用一次,返回初始化完成的IHost |
值得注意的源码细节:IHostBuilder上UseServiceProviderFactory<TContainerBuilder>(Func<HostBuilderContext, IServiceProviderFactory<TContainerBuilder>> factory)重载在#if NET分支下提供了默认接口方法(DIM)实现——默认抛出NotSupportedException。这是为了兼容旧版(如 2.2.0.0)只实现了非 Func 重载的IHostBuilder实现,使其在现代 .NET 上加载时不抛TypeLoadException。这一兼容性设计被 HostBuilderContextTests.cs 中的IHostBuilderDefaultInterfaceMethodTests显式验证。
3. HostBuilderContext —— 构建上下文
HostBuilderContext.cs 是构建过程中传递给各委托的上下文对象:
public class HostBuilderContext { public IHostEnvironment HostingEnvironment { get; set; } public IConfiguration Configuration { get; set; } public IDictionary<object, object> Properties { get; } }其构造函数强制要求传入非空的properties字典(ArgumentNullException.ThrowIfNull),该字典与外部传入的字典共享引用,即构建过程中在Properties里写入的键值会实时反映到外部。对应行为均有 HostBuilderContextTests.cs 的测试覆盖(如Properties_SharedWithConstructorDictionary验证共享语义)。
三、核心原语:IHostedService 与 BackgroundService
1. IHostedService —— 托管服务契约
文档明确指出,托管服务(hosted service)是宿主提供的基本原语,也是 ASP.NET Core 等应用模型与宿主集成的入口。其定义极其精简(IHostedService.cs):
public interface IHostedService { Task StartAsync(CancellationToken cancellationToken); Task StopAsync(CancellationToken cancellationToken); }StartAsync:当应用宿主准备好启动服务时触发;传入的CancellationToken表示启动过程已被中止;StopAsync:当应用宿主执行优雅关闭时触发;传入的CancellationToken表示关闭过程不再要求优雅。
2. BackgroundService —— 长运行任务的现成基类
开发者通常不需要自己实现IHostedService的完整生命周期,继承 BackgroundService.cs 即可:
public abstract class BackgroundService : IHostedService, IDisposable { public virtual Task? ExecuteTask => _executeTask; protected abstract Task ExecuteAsync(CancellationToken stoppingToken); public virtual Task StartAsync(CancellationToken cancellationToken); public virtual Task StopAsync(CancellationToken cancellationToken); public virtual void Dispose(); }其内部工作机制值得深入理解(源码级):
- 启动:
StartAsync内部通过CancellationTokenSource.CreateLinkedTokenSource(cancellationToken)创建链接令牌,将启动令牌与停止令牌关联;随后在后台执行ExecuteAsync(stoppingToken)并保存返回的Task到ExecuteTask。StartAsync本身总是返回已完成的任务,ExecuteAsync的任何结果统一由 Host 处理。 - 停止:
StopAsync先取消_stoppingCts向执行中的ExecuteAsync发送停止信号,再等待任务结束;在#if NET分支使用_executeTask.WaitAsync(cancellationToken)实现"等待执行任务完成或停止令牌触发",并刻意SuppressThrowing忽略OperationCanceledException(因为取消执行任务必然抛出该异常,属预期行为);非 NET 目标框架(如 .NET Framework)则退化为Task.WhenAny的等值实现。 - 执行中的取消令牌:传入
ExecuteAsync的stoppingToken正是文档所述的"当StopAsync被调用时触发"的令牌,这是后台任务响应优雅关闭的标准通道。
一个标准的定时型后台服务示例(ExecuteAsync返回代表长运行操作生命周期的任务,stoppingToken用于响应关闭):
public sealed class TimedHostedService : BackgroundService { private readonly ILogger<TimedHostedService> _logger; public TimedHostedService(ILogger<TimedHostedService> logger) => _logger = logger; protected override async Task ExecuteAsync(CancellationToken stoppingToken) { _logger.LogInformation("Timed Hosted Service running."); using PeriodicTimer timer = new(TimeSpan.FromSeconds(5)); try { while (await timer.WaitForNextTickAsync(stoppingToken)) { _logger.LogInformation("Timed Hosted Service is doing background work."); } } catch (OperationCanceledException) { _logger.LogInformation("Timed Hosted Service is stopping."); } } }四、生命周期管理:应用级、宿主级与服务级三层协同
1. IHostApplicationLifetime —— 应用级生命周期令牌
IHostApplicationLifetime.cs 让消费方订阅应用生命周期事件(该接口被设计为不可由用户替换,宿主内部统一实现):
| 成员 | 触发时机 |
|---|---|
CancellationToken ApplicationStarted | 宿主已完全启动、即将等待优雅关闭时触发 |
CancellationToken ApplicationStopping | 宿主开始优雅关闭时触发(可能仍有请求在途,关闭会阻塞直到所有回调完成) |
CancellationToken ApplicationStopped | 宿主完成优雅关闭后触发(所有请求应已结束,应用不会退出直到所有回调完成) |
void StopApplication() | 主动请求终止当前应用 |
示例:在ApplicationStopping上注册清理回调,确保关闭前完成资源释放:
public class GracefulShutdownHandler : IHostedService { private readonly IHostApplicationLifetime _lifetime; public GracefulShutdownHandler(IHostApplicationLifetime lifetime) => _lifetime = lifetime; public Task StartAsync(CancellationToken cancellationToken) { _lifetime.ApplicationStopping.Register(() => { // 执行清理:刷新缓冲、释放连接、通知对端下线等 }); return Task.CompletedTask; } public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask; }2. IHostLifetime —— 宿主级启动/停止协调
IHostLifetime.cs 负责跟踪宿主本身的生命周期:
WaitForStartAsync(CancellationToken):在IHost.StartAsync开头调用,会阻塞后续启动流程直到其完成,可用来延迟启动直到外部事件就绪(例如控制台宿主等待 Ctrl+C、服务宿主等待系统服务管理器信号);StopAsync(CancellationToken):由IHost.StopAsync调用,指示宿主正在停止、到了关闭时刻。
3. IHostedLifecycleService —— 托管服务的精细生命周期钩子
当应用需要在StartAsync/StopAsync前后插入逻辑时,可实现 IHostedLifecycleService.cs(它继承IHostedService):
public interface IHostedLifecycleService : IHostedService { Task StartingAsync(CancellationToken cancellationToken); // StartAsync 之前 Task StartedAsync(CancellationToken cancellationToken); // StartAsync 之后 Task StoppingAsync(CancellationToken cancellationToken); // StopAsync 之前 Task StoppedAsync(CancellationToken cancellationToken); // StopAsync 之后 }由此形成的完整启动序列为:StartingAsync→StartAsync→StartedAsync;关闭序列为:StoppingAsync→StopAsync→StoppedAsync。
五、环境抽象:IHostEnvironment 与标准环境名
1. IHostEnvironment —— 托管环境信息
IHostEnvironment.cs 提供应用运行环境信息,宿主会自动从配置填充这些属性:
| 属性 | 含义与自动填充规则 |
|---|---|
EnvironmentName | 环境名称,宿主自动设置为配置中environment键的值 |
ApplicationName | 应用名称,宿主自动设置为包含应用入口点的程序集名 |
ContentRootPath | 包含应用内容文件的目录的绝对路径 |
ContentRootFileProvider | 指向ContentRootPath的IFileProvider |
对应的配置键常量定义在 HostDefaults.cs:applicationName、environment、contentRoot。这些键既可用作宿主配置(Host configuration)的键名,也可通过环境变量(如DOTNET_ENVIRONMENT、ASPNETCORE_ENVIRONMENT)注入。
2. Environments —— 标准环境名常量
Environments.cs 定义了三个常用环境名:
Development:开发环境,可启用生产环境不应暴露的特性;出于性能成本考虑,作用域验证与依赖验证只在开发环境执行;Staging:预发布环境,用于上线前验证应用变更;Production:生产环境,应配置为最大化安全、性能与健壮性。
3. 环境判断扩展方法
HostEnvironmentEnvExtensions.cs 为IHostEnvironment提供了便捷判断方法:
public static bool IsDevelopment(this IHostEnvironment hostEnvironment); public static bool IsStaging(this IHostEnvironment hostEnvironment); public static bool IsProduction(this IHostEnvironment hostEnvironment); public static bool IsEnvironment(this IHostEnvironment hostEnvironment, string environmentName);核心实现IsEnvironment使用StringComparison.OrdinalIgnoreCase做大小写不敏感比较,因此"development"、"Development"等价。对应测试见 HostEnvironmentEnvExtensionsTests.cs 与 EnvironmentsTests.cs(后者验证三个常量值分别为"Development"、"Staging"、"Production")。
典型用法:
public void Configure(IHostEnvironment env, ILoggerFactory loggerFactory) { if (env.IsDevelopment()) { // 开发环境专属:详细日志、开发异常页等 } }兼容性说明:旧接口
IHostingEnvironment(IHostingEnvironment.cs)已被标记[Obsolete],官方推荐统一使用IHostEnvironment;对应旧扩展类HostingEnvironmentExtensions也随其一起标记为 obsolete。应用代码新开发应直接面向IHostEnvironment。
六、注册托管服务:AddHostedService 扩展方法
托管服务通过 ServiceCollectionHostedServiceExtensions.cs 注册到IServiceCollection:
// 泛型重载:按类型注册 public static IServiceCollection AddHostedService<THostedService>(this IServiceCollection services) where THostedService : class, IHostedService; // 工厂重载:按委托创建实例 public static IServiceCollection AddHostedService<THostedService>(this IServiceCollection services, Func<IServiceProvider, THostedService> implementationFactory) where THostedService : class, IHostedService;源码实现要点:
- 两者都通过
TryAddEnumerable(ServiceDescriptor.Singleton<IHostedService, THostedService>())注册,即注册的抽象是IHostedService本身,而不是具体类型THostedService; - 使用
TryAddEnumerable保证同一实现类型不会重复注册; - 生命周期为单例(Singleton)。
文档特别提醒:若要同时注册具体类型本身,必须单独注册。官方给出的推荐写法:
services.AddSingleton<SomeService>(); services.AddHostedService(sp => sp.GetRequiredService<SomeService>());这样SomeService及其依赖由 DI 容器统一管理,托管服务通过工厂解析同一单例实例。
七、运行与停止宿主:HostingAbstractionsHostExtensions
HostingAbstractionsHostExtensions.cs 为IHost提供同步/异步运行辅助方法,是控制台应用、Windows 服务与 ASP.NET Core 启动代码的公共基础:
| 方法 | 行为 |
|---|---|
Start(this IHost host) | 同步启动宿主 |
StopAsync(this IHost host, TimeSpan timeout) | 在指定超时内优雅停止,超时后服务器可终止剩余活动连接 |
WaitForShutdown(this IHost host) | 阻塞调用线程直到通过 Ctrl+C 或 SIGTERM 触发关闭 |
Run(this IHost host) | 运行应用并阻塞直到关闭触发且所有IHostedService停止 |
RunAsync(this IHost host, CancellationToken token) | 异步版本,token 触发或关闭触发时完成;运行结束后自动释放宿主 |
WaitForShutdownAsync(this IHost host, CancellationToken token) | 返回在关闭触发时完成的Task |
实现细节:WaitForShutdownAsync从host.Services解析IHostApplicationLifetime,将外部 token 注册为调用StopApplication(),然后等待ApplicationStopping令牌;在#if NET分支通过Task.Delay(Timeout.Infinite, ...)配合SuppressThrowing实现阻塞。RunAsync在finally中优先走IAsyncDisposable.DisposeAsync(),否则回退到同步Dispose()。
对应地,HostingAbstractionsHostBuilderExtensions.cs 为IHostBuilder提供Start()/StartAsync()快捷方法:内部先Build()再StartAsync()。
典型控制台应用入口(结合泛型主机实现):
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; HostApplicationBuilder builder = Host.CreateApplicationBuilder(args); builder.Services.AddHostedService<TimedHostedService>(); using IHost host = builder.Build(); await host.RunAsync();其中RunAsync负责:启动托管服务 → 等待ApplicationStopping(Ctrl+C/SIGTERM)→ 优雅停止所有托管服务 → 释放宿主。
八、新一代宿主构建抽象:IHostApplicationBuilder
面向 .NET 7+ 的HostApplicationBuilder模式基于 IHostApplicationBuilder.cs 抽象,其成员比IHostBuilder更贴近"构建一个应用"的直觉:
| 成员 | 作用 |
|---|---|
Properties | 构建期间组件共享状态的中心位置 |
Configuration(IConfigurationManager) | 可变配置集合,可继续追加配置源,追加后其当前视图立即更新 |
Environment | 宿主环境信息 |
Logging(ILoggingBuilder) | 日志提供程序组合点 |
Metrics(IMetricsBuilder) | 启用指标并指定输出方向的构建器 |
Services | 应用服务集合(用户服务与框架服务) |
ConfigureContainer<TContainerBuilder>(factory, configure) | 注册第三方容器工厂;IServiceProvider在构建时创建,因此configure委托会在所有服务注册完成后运行;多次调用会替换先前存储的工厂与委托 |
九、异常与资源类型
1. HostAbortedException
HostAbortedException.cs 是当IHost被停止以表示"宿主正在优雅停止"时抛出的密封异常。文档明确:该异常不应由用户代码抛出或捕获。它提供默认消息(来自Strings.resx的SR.HostAbortedExceptionMessage)、自定义消息与内部异常三个构造函数重载。
2. 生命周期接口的演进
目录中还保留了IApplicationLifetime.cs与EnvironmentName.cs等历史类型,分别与IHostingEnvironment配套使用,随旧抽象一并废弃;当前路线统一收敛到IHostApplicationLifetime+IHostEnvironment+Environments的新三元组。
十、源码布局、测试与质量门槛
1. 源码与测试组织
- 接口/基类/扩展方法:
src/libraries/Microsoft.Extensions.Hosting.Abstractions/src/(23 个源文件 +Strings.resx资源 +PACKAGE.md包说明) - 单元测试:
src/libraries/Microsoft.Extensions.Hosting.Abstractions/tests/,含 EnvironmentsTests.cs、HostBuilderContextTests.cs、HostDefaultsTests.cs、HostEnvironmentEnvExtensionsTests.cs - 参考程序集/API 面:
src/libraries/Microsoft.Extensions.Hosting.Abstractions/ref/Microsoft.Extensions.Hosting.Abstractions.cs - 解决方案:
src/libraries/Microsoft.Extensions.Hosting.Abstractions/Microsoft.Extensions.Hosting.Abstractions.slnx
2. 贡献门槛(Contribution Bar)
原文档明确该库接受新特性、新 API、bug 修复与性能改进(详见 src/libraries/README.md 的主贡献门槛说明)。同时文档也坦诚:这些 API 与功能已成熟,目前没有积极的投资计划,但对更深入的投资想法持开放态度,未来理想的投资方向包括:
- 支持全部 .NET Core 应用模型:WinForms、WPF、UWP、Xamarin、短运行(批量)控制台任务、Blazor(客户端);
- 为托管服务提供idle/pause(空闲/暂停)支持;
- 提供更多托管服务基类,例如timer-based(基于定时器)与trigger-based(基于触发器)的基类。
3. 部署方式
Microsoft.Extensions.Hosting.Abstractions有两个交付通道(文档明确说明):
- 已包含在ASP.NET Core 共享框架(shared framework)中,使用 ASP.NET Core 的应用开箱即得;
- 同时作为out-of-band(OOB)包独立发布,可被任意项目直接引用——这正是它同时服务于长运行控制台应用、Windows 服务与 ASP.NET Core 三类场景的包分发基础。
十一、从抽象到实现:理解抽象层在 .NET 托管体系中的位置
综合本文分析,可以梳理出该抽象包在托管体系中的分层职责:
┌─────────────────────────────────────────────────────────┐ │ 应用模型(ASP.NET Core / Worker / Windows 服务…) │ │ └─ 通过 IHostedService / IHostedLifecycleService │ ├─────────────────────────────────────────────────────────┤ │ Microsoft.Extensions.Hosting.Abstractions(本文主题) │ │ IHost · IHostBuilder · IHostEnvironment │ │ IHostedService · BackgroundService │ │ IHostApplicationLifetime · IHostLifetime │ │ AddHostedService / Run / RunAsync 等扩展 │ ├─────────────────────────────────────────────────────────┤ │ Microsoft.Extensions.Hosting(实现包,位于本仓库 │ │ src/libraries/Microsoft.Extensions.Hosting/) │ │ HostBuilder / Host / ConsoleLifetime 等具体实现 │ └─────────────────────────────────────────────────────────┘抽象层只定义契约,实现层提供HostBuilder、Host等具体类型;应用模型(如 ASP.NET Core 的WebApplication)再基于这两层组装。这种"抽象与实现分离"的设计,让上层应用模型可以稳定依赖接口、让第三方容器(Autofac 等)可以通过IServiceProviderFactory无侵入接入、也让测试可以用最小桩实现(如HostBuilderContextTests中的MinimalHostBuilder)验证契约行为。
结语
Microsoft.Extensions.Hosting.Abstractions虽是一个"纯抽象"包,却是整个 .NET 托管体系的契约基石。理解IHost/IHostBuilder的构建与运行两阶段、掌握IHostedService/BackgroundService的启动停止语义、善用IHostApplicationLifetime与IHostedLifecycleService的生命周期钩子,是编写健壮的后台任务、Windows 服务与跨模型复用代码的必备技能。深入阅读本仓库 Microsoft.Extensions.Hosting.Abstractions 源码目录 及其测试,可以让你对"宿主如何管理你的代码"有完整的源码级认知。
- 语言运行时
- 标准库
- JIT编译
- 编译器
【免费下载链接】runtime
.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
相关推荐
linkding 托管部署指南:托管服务、托管平台与自托管方案全解析
linkding 托管部署指南:托管服务、托管平台与自托管方案全解析 linkding 是一个定位为"极简、快速、易于用 Docker 部署"的自托管书签管理器
后端前端Expert云服务:托管服务与SaaS方案深度解析
Expert云服务:托管服务与SaaS方案深度解析 引言:为什么需要Elixir语言服务器的云服务? 在当今云原生时代,开发工具正在从本地安装向云端服务迁移。E
开发工具IDE构建高性能语言应用:47万英语词汇数据库的完整技术方案
构建高性能语言应用:47万英语词汇数据库的完整技术方案 在自然语言处理和语言应用开发领域,高质量词汇数据库是技术架构的核心基础。english words项目提
数据集
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考