IHostedService实现中DBContext为空及对象已释放异常问题
问题分析与解决方案
嘿,先给你吃个定心丸——你一开始写的InitializeCacheService代码其实是完全正确的!你自己也排查出来了,最初的“DbContext为空”问题是因为CacheLogic里没正确初始化context,和HostedService的实现没关系~
接下来重点说你后来遇到的System.ObjectDisposedException问题,原因很明确:
- 你在
InitializeCacheService的using(scope)块里创建了DbContext,这个scope和里面的DbContext会在using块结束后被自动释放 - 但你把这个已经绑定到当前scope的DbContext传给了单例的
CacheLogic,后续CacheLogic再尝试用这个DbContext的时候,它已经被Dispose了,自然就抛出这个异常
正确的做法:单例服务中使用Scoped的DbContext
因为DbContext是Scoped生命周期(每次请求/scope创建一次),而单例服务的生命周期和应用一致,所以单例不能直接持有DbContext实例。正确的方式是让单例依赖IServiceScopeFactory,每次需要操作数据库时,临时创建一个scope并从中获取DbContext,用完后让scope自动释放。
修改后的CacheLogic示例:
public class CacheLogic { private readonly IMemoryCache _cache; private readonly IServiceScopeFactory _scopeFactory; // 注入IServiceScopeFactory,而非直接注入DbContext public CacheLogic(IMemoryCache cache, IServiceScopeFactory scopeFactory) { _cache = cache; _scopeFactory = scopeFactory; } public void LoadProfileCache() { // 每次数据库操作都创建独立的scope using (var scope = _scopeFactory.CreateScope()) { var context = scope.ServiceProvider.GetRequiredService<MyContext>(); // 执行你的查询逻辑 var profileData = context.Profiles.ToList(); _cache.Set("ProfileCache", profileData); } // using块结束,scope和内部的DbContext自动被释放 } // 如果有其他需要访问数据库的方法,同样用scope包裹 public Profile GetProfile(int profileId) { using (var scope = _scopeFactory.CreateScope()) { var context = scope.ServiceProvider.GetRequiredService<MyContext>(); return context.Profiles.FirstOrDefault(p => p.Id == profileId); } } }
注册单例的CacheLogic
在Startup.cs的ConfigureServices里添加:
services.AddSingleton<CacheLogic>();
额外提醒
DI容器的生命周期规则一定要牢记:
- 单例服务不能直接依赖Scoped/Transient服务(除非通过
IServiceScopeFactory动态获取) - Scoped服务可以依赖Singleton/Scoped服务
- Transient服务可以依赖任何生命周期的服务
这样调整后,你就不会再遇到ObjectDisposedException的问题了~
内容的提问来源于stack exchange,提问作者PNR
相关产品推荐
相关产品推荐

