0

0

c# 在ASP.NET Core中管理和取消后台任务

煙雲

煙雲

发布时间:2026-01-02 08:48:39

|

647人浏览过

|

来源于php中文网

原创

在 ASP.NET Core 中注册可取消的后台服务需继承 BackgroundService 基类,重写 ExecuteAsync 并全程传递 CancellationToken;注册时调用 AddHostedService(),避免生命周期冲突,优先使用 PeriodicTimer 实现定时任务。

c# 在asp.net core中管理和取消后台任务

如何在 ASP.NET Core 中注册可取消的后台服务

ASP.NET Core 的 IHostedService 是管理长时运行后台任务的标准方式,但原生不自动传递取消信号——必须显式接收 CancellationToken 并在关键阻塞点响应它。直接在 ExecuteAsync 中忽略 cancellationToken 参数,会导致应用关闭时任务强行终止,可能丢失数据或破坏状态。

正确做法是将传入的 CancellationToken 透传给所有支持它的异步 API(如 Task.DelayHttpClient.GetAsync),并在非托管等待(如 Thread.Sleep)前手动检查 IsCancellationRequested

  • 注册时使用 AddHostedService(),而非普通 AddSingleton
  • 构造函数中不要捕获 IServiceProvider 来解析服务——可能引发作用域生命周期冲突;改用 IServiceScopeFactory 按需创建作用域
  • 若任务需定期执行,优先用 PeriodicTimer(.NET 6+)替代 Task.Delay 循环,它原生支持 CancellationToken
public class DataSyncService : IHostedService, IDisposable
{
    private readonly IServiceScopeFactory _scopeFactory;
    private Timer? _timer;

    public DataSyncService(IServiceScopeFactory scopeFactory)
    {
        _scopeFactory = scopeFactory;
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        _timer = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromMinutes(5));
        return Task.CompletedTask;
    }

    private async void DoWork(object? state)
    {
        using var scope = _scopeFactory.CreateScope();
        var dbContext = scope.ServiceProvider.GetRequiredService();

        try
        {
            await dbContext.SyncDataAsync(cancellationToken); // 假设该方法接受 token
        }
        catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested)
        {
            // 正常退出,不记录错误
        }
        catch (Exception ex)
        {
            // 记录未预期异常
        }
    }

    public async Task StopAsync(CancellationToken cancellationToken)
    {
        _timer?.Change(Timeout.Infinite, 0);
        _timer?.Dispose();
        await Task.Delay(100, cancellationToken); // 给正在执行的 DoWork 留出收尾时间
    }

    public void Dispose() => _timer?.Dispose();
}

为什么 BackgroundService 基类比裸实现 IHostedService 更安全

BackgroundService微软提供的抽象基类,它封装了启动/停止协调逻辑,并确保 StopAsync 被调用后,正在运行的 ExecuteAsync 任务能自然完成(除非超时)。裸写 IHostedService 容易漏掉对 cancellationToken 的传播,或在 StopAsync 中过早释放资源,导致 ObjectDisposedException

  • BackgroundServiceStopAsync 默认等待 ExecuteAsync 返回,且会把宿主的 cancellationToken 传入其中
  • ExecuteAsync 内部有长时间无响应的同步操作(如文件锁、外部 API 同步调用),仍需自行添加超时和中断逻辑
  • 不要在 ExecuteAsync 中用 while (true) + await Task.Delay 无限循环——应改为 while (!stoppingToken.IsCancellationRequested)

常见取消失败场景及修复方式

即使用了 CancellationToken,后台任务仍可能无法及时响应取消,典型表现是应用关闭后进程卡住几秒甚至几十秒才退出。根本原因通常是某处阻塞操作没受 token 控制。

版纳武林DIY企业建站系统
版纳武林DIY企业建站系统

系统简介1:安全可靠: 在微软主推的.NET开发平台上,采用业界领先的ASP.NET技术和C#语言开发,不仅安全可靠,并能保证系统的高性能运行。2:简单易用:版纳武林DIY企业建站系统真正做到以人为本、以用户体验为中心,能使您快速搭建您的网站。后台管理操作简单,一目了然,没有夹杂多余的功能和广告。3:布局易改:版纳武林DIY企业建站系统采用的是博客形式的风格管理,让您真正感受到我的地盘听我的.4:

下载
  • HttpClient 请求未传入 token:必须用 GetAsync(uri, cancellationToken),不能只用 GetAsync(uri)
  • 数据库查询未启用取消:EF Core 的 ToListAsync(cancellationToken) 和 Dapper 的 QueryAsync(..., cancellationToken) 都需显式传参
  • 自定义同步等待未检查 token:例如 while (!token.IsCancellationRequested) { Thread.Sleep(100); } 应改为 await Task.Delay(100, token)
  • 第三方 SDK 不支持 token:需包裹在 Task.Run(() => { ... }, cancellationToken) 中,并在内部定期轮询 token.IsCancellationRequested

如何测试后台服务的取消行为

本地调试时,Ctrl+C 或发送 SIGTERM 信号即可触发取消流程,但自动化测试需模拟宿主生命周期。不要直接 new 实例并调用 StartAsync——缺少 IHostApplicationLifetime 支持,StopAsync 不会被自动调用。

  • 使用 Host.CreateDefaultBuilder() 构建测试宿主,注入你的服务,再调用 host.StopAsync()
  • 在测试中用 Task.Delay(100).Wait(cancellationToken) 模拟耗时操作,并验证是否在指定时间内完成
  • 注意:BackgroundService 的默认超时是 5 秒(由 HostOptions.ShutdownTimeout 控制),测试时可临时缩短它以便快速验证

真正难的不是加 cancellationToken,而是确认每一个 await 点、每一次 IO 调用、每一段同步等待都真正尊重了它——哪怕一个地方漏掉,整个取消链就断了。

相关专题

更多
while的用法
while的用法

while的用法是“while 条件: 代码块”,条件是一个表达式,当条件为真时,执行代码块,然后再次判断条件是否为真,如果为真则继续执行代码块,直到条件为假为止。本专题为大家提供while相关的文章、下载、课程内容,供大家免费下载体验。

81

2023.09.25

登录token无效
登录token无效

登录token无效解决方法:1、检查token的有效期限,如果token已经过期,需要重新获取一个新的token;2、检查token的签名,如果签名不正确,需要重新获取一个新的token;3、检查密钥的正确性,如果密钥不正确,需要重新获取一个新的token;4、使用HTTPS协议传输token,建议使用HTTPS协议进行传输 ;5、使用双因素认证,双因素认证可以提高账户的安全性。

6048

2023.09.14

登录token无效怎么办
登录token无效怎么办

登录token无效的解决办法有检查Token是否过期、检查Token是否正确、检查Token是否被篡改、检查Token是否与用户匹配、清除缓存或Cookie、检查网络连接和服务器状态、重新登录或请求新的Token、联系技术支持或开发人员等。本专题为大家提供token相关的文章、下载、课程内容,供大家免费下载体验。

783

2023.09.14

token怎么获取
token怎么获取

获取token值的方法:1、小程序调用“wx.login()”获取 临时登录凭证code,并回传到开发者服务器;2、开发者服务器以code换取,用户唯一标识openid和会话密钥“session_key”。想了解更详细的内容,可以阅读本专题下面的文章。

1052

2023.12.21

token什么意思
token什么意思

token是一种用于表示用户权限、记录交易信息、支付虚拟货币的数字货币。可以用来在特定的网络上进行交易,用来购买或出售特定的虚拟货币,也可以用来支付特定的服务费用。想了解更多token什么意思的相关内容可以访问本专题下面的文章。

1095

2024.03.01

Java 并发编程高级实践
Java 并发编程高级实践

本专题深入讲解 Java 在高并发开发中的核心技术,涵盖线程模型、Thread 与 Runnable、Lock 与 synchronized、原子类、并发容器、线程池(Executor 框架)、阻塞队列、并发工具类(CountDownLatch、Semaphore)、以及高并发系统设计中的关键策略。通过实战案例帮助学习者全面掌握构建高性能并发应用的工程能力。

54

2025.12.01

数据库三范式
数据库三范式

数据库三范式是一种设计规范,用于规范化关系型数据库中的数据结构,它通过消除冗余数据、提高数据库性能和数据一致性,提供了一种有效的数据库设计方法。本专题提供数据库三范式相关的文章、下载和课程。

334

2023.06.29

如何删除数据库
如何删除数据库

删除数据库是指在MySQL中完全移除一个数据库及其所包含的所有数据和结构,作用包括:1、释放存储空间;2、确保数据的安全性;3、提高数据库的整体性能,加速查询和操作的执行速度。尽管删除数据库具有一些好处,但在执行任何删除操作之前,务必谨慎操作,并备份重要的数据。删除数据库将永久性地删除所有相关数据和结构,无法回滚。

2068

2023.08.14

php源码安装教程大全
php源码安装教程大全

本专题整合了php源码安装教程,阅读专题下面的文章了解更多详细内容。

74

2025.12.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Java 教程
Java 教程

共578课时 | 40.6万人学习

国外Web开发全栈课程全集
国外Web开发全栈课程全集

共12课时 | 0.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号