当需要比 BackgroundService 提供的有限控制更多的控制时,可以实现自己的 IHostedService。IHostedService 是 .NET 中所有长期运行服务的基础接口。自定义实现通过 AddHostedService<THostedService>(IServiceCollection) 扩展方法注册。
本教程介绍:
- 实现
IHostedService和IAsyncDisposable接口。 - 创建基于计时器的服务。
- 使用依赖项注入和日志记录注册自定义实现。
所有“.NET 中的 Workers”示例源代码均可在示例代码浏览器下载。
先决条件
- .NET 8.0 SDK 或更高版本。
- .NET 集成开发环境(IDE),例如 Visual Studio。
创建新项目
使用 Visual Studio 时,选择“文件 > 新建 > 项目”,在“创建新项目”对话框搜索“辅助角色服务”,然后选择相应模板。
使用 .NET CLI 时,在工作目录打开终端并运行以下命令,将 <Project.Name> 替换为项目名称:
创建 Worker 项目(.NET CLI)
dotnet new worker --name <Project.Name>
更多信息见 dotnet new worker。
如果使用 Visual Studio Code,可以在集成终端运行 .NET CLI 命令,参见 Visual Studio Code 集成终端。
创建计时器服务
基于计时器的后台服务使用 System.Threading.Timer 类。计时器触发 DoWork 方法。在 StopAsync(CancellationToken) 中禁用计时器;服务容器通过 IAsyncDisposable.DisposeAsync() 释放服务时,也释放计时器。
将模板中的 Worker 内容替换为以下 C# 代码,并将文件重命名为 TimerService.cs:
TimerService.cs
namespace App.TimerHostedService;
public sealed class TimerService(ILogger<TimerService> logger) : IHostedService, IAsyncDisposable
{
private readonly Task _completedTask = Task.CompletedTask;
private int _executionCount = 0;
private Timer? _timer;
public Task StartAsync(CancellationToken stoppingToken)
{
logger.LogInformation("{Service} is running.", nameof(TimerHostedService));
_timer = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromSeconds(5));
return _completedTask;
}
private void DoWork(object? state)
{
int count = Interlocked.Increment(ref _executionCount);
logger.LogInformation(
"{Service} is working, execution count: {Count:#,0}",
nameof(TimerHostedService),
count);
}
public Task StopAsync(CancellationToken stoppingToken)
{
logger.LogInformation(
"{Service} is stopping.", nameof(TimerHostedService));
_timer?.Change(Timeout.Infinite, 0);
return _completedTask;
}
public async ValueTask DisposeAsync()
{
if (_timer is IAsyncDisposable timer)
{
await timer.DisposeAsync();
}
_timer = null;
}
}
Worker 是 BackgroundService 的子类。修改后,TimerService 实现 IHostedService 和 IAsyncDisposable 接口。
TimerService 是 sealed 类,并将 DisposeAsync 调用级联到它的 _timer 实例。有关级联释放模式,参见实现 DisposeAsync 方法。
调用 StartAsync 时,计时器会被实例化并启动。
计时器不会等待上一次回调完成。
Timer不会等待上一次DoWork执行完毕,因此这种方法不适合所有场景。Interlocked.Increment以原子方式递增执行计数器,避免多个线程同时修改_executionCount。
将现有的 Program 内容替换为:
Program.cs
using App.TimerHostedService;
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddHostedService<TimerService>();
IHost host = builder.Build();
host.Run();
服务在 Program.cs 中通过 AddHostedService 扩展方法注册。注册 BackgroundService 子类时也使用同一个扩展方法,因为它们都实现了 IHostedService 接口。
更多信息见 .NET 中的依赖项注入。
验证服务功能
从 Visual Studio 运行应用时,按 F5,或选择“调试 > 开始调试”。使用 .NET CLI 时,在工作目录执行:
运行项目(.NET CLI)
dotnet run
更多信息见 dotnet run。
让应用运行一段时间,产生多次计数递增。输出应类似原文所示:
原文示例日志
info: App.TimerHostedService.TimerService[0]
TimerHostedService is running.
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
Content root path: .\timer-service
info: App.TimerHostedService.TimerService[0]
TimerHostedService is working, execution count: 1
info: App.TimerHostedService.TimerService[0]
TimerHostedService is working, execution count: 2
info: App.TimerHostedService.TimerService[0]
TimerHostedService is working, execution count: 3
info: App.TimerHostedService.TimerService[0]
TimerHostedService is working, execution count: 4
info: Microsoft.Hosting.Lifetime[0]
Application is shutting down...
info: App.TimerHostedService.TimerService[0]
TimerHostedService is stopping.
从 Visual Studio 运行时,选择“调试 > 停止调试”。从控制台运行时,按 Ctrl + C 发出取消信号。
另请参阅
来源:实现 IHostedService 接口,Microsoft Learn,原页更新于2026年1月24日。本文为官方中文教程的排版和措辞整理,适用于 .NET 8.0 或更高版本。StopAsync 文档链接指向示例实际实现的 IHostedService 接口。正文采用 CC BY 4.0,示例代码采用 MIT 许可。版权归 Microsoft 和贡献者所有。
代码许可:The MIT License (MIT)。Copyright (c) Microsoft Corporation。
特此免费授予任何获得本软件及相关文档文件(“软件”)副本的人不受限制地处理软件的权利,包括但不限于使用、复制、修改、合并、发布、分发、再许可和/或出售软件副本,并允许软件接收者如此行事,条件是:上述版权声明和本许可声明须包含在软件的所有副本或实质性部分中。软件按原样提供,不作任何明示或默示保证,包括但不限于适销性、特定用途适用性和不侵权保证。无论依据合同、侵权或其他法律理论,作者或版权持有人均不对因软件、软件使用或其他软件交易而产生、引起或相关的任何索赔、损害或其他责任负责。
原始代码许可证全文
Copyright (c) Microsoft Corporation
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the “Software”), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial
portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.












暂无评论内容