You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET Core中IHostedService报对象已释放错误该如何正确实现?

问题根因

你触发ObjectDisposedException的核心原因是构造函数中的服务作用域被提前释放:

  • 构造函数中你用using语句创建了IServiceScope,当using代码块执行结束后,整个scope包括其下的ServiceProvider都会被自动销毁,你赋值的_provider本质是已经被释放的对象,后续Timer回调调用Purge方法访问该对象时就会抛出释放异常。

同时你的代码还存在3个功能性问题:

  1. 时间判断逻辑完全错误:要删除超过留存时长的通知,应该筛选创建时间早于当前时间减去留存时长的记录,你当前写的CreatedDate > {deletedate}(且deletedate是当前时间加留存时长)完全匹配不到需要删除的数据
  2. 只拼接了SQL字符串,没有实际执行删除操作
  3. Timer回调没有处理异步和异常,一旦触发未捕获异常会直接导致后台服务崩溃

修正后的完整代码

public class PurgeService : IHostedService, IDisposable
{
    private readonly IServiceProvider _rootProvider;
    private Timer _timer;
    // 直接注入根服务提供者,不要提前创建scope
    public PurgeService(IServiceProvider rootProvider)
    {
        _rootProvider = rootProvider;
    }

    public void Dispose()
    {
        _timer?.Dispose();
    }

    // 每次执行任务时单独创建作用域
    private async Task Purge()
    {
        try
        {
            // 为本次任务创建独立的服务作用域,执行完自动释放
            using var scope = _rootProvider.CreateScope();
            var serviceProvider = scope.ServiceProvider;
            var dbContext = serviceProvider.GetRequiredService<ApplicationDBContext>();
            var setting = await dbContext.AppSet.FirstAsync();
            // 计算删除阈值:当前时间 减去 允许留存的小时数,早于该时间的通知需要删除
            var deleteThreshold = DateTime.Now.AddHours(-setting.PurgeTimer);
            // 执行SQL删除,Interpolated方式避免SQL注入风险
            await dbContext.Database.ExecuteSqlInterpolatedAsync(
                $"DELETE FROM Notifications WHERE CreatedDate < {deleteThreshold}"
            );
        }
        catch (Exception ex)
        {
            // 此处可接入日志组件记录错误,避免服务意外崩溃
        }
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        // 适配异步方法,避免async void导致的异常逃逸问题
        _timer = new Timer(async _ => await Purge(), null, TimeSpan.Zero, TimeSpan.FromSeconds(10));
        return Task.CompletedTask;
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        _timer?.Change(Timeout.Infinite, 0);
        return Task.CompletedTask;
    }
}

注册逻辑

原有注册逻辑不需要修改,保持以下代码即可:

services.AddHostedService<PurgeService>();

内容的提问来源于stack exchange,提问作者T0bi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 14:24:03