Hangfire与依赖注入Scoped问题:过滤器与Job共享服务实例
问题根源与解决方案
你当前的问题核心是:在Startup注册Hangfire过滤器时,直接从根服务提供者获取了IUnitofWork实例——根容器下获取Scoped服务会导致这个实例变成"伪单例",而Job里的IUnitofWork是每个Job激活时创建的独立Scope实例,自然两者无法共享。
以下是具体修正步骤:
1. 修改HangfireSessionFilter,从Job上下文获取当前Scope的IUnitofWork
移除构造函数注入,改为在过滤器执行时从当前Job的服务Scope中解析实例:
public class HangfireSessionFilter : JobFilterAttribute, IServerFilter { public void OnPerformed(PerformedContext filterContext) { var unitOfWork = filterContext.ServiceProvider.GetService<IUnitofWork>(); unitOfWork?.Commit(); } public void OnPerforming(PerformingContext context) { var unitOfWork = context.ServiceProvider.GetService<IUnitofWork>(); if (unitOfWork == null) return; var hash = unitOfWork.GetHashCode(); unitOfWork.BeginTransaction(); } }
2. 调整Startup中的Hangfire配置
注册过滤器时,无需传入根容器的IUnitofWork,直接使用无参实例即可:
services.AddHangfire((provider, config) => { config.UseActivator(new ServiceJobActivator(provider.GetService<IServiceScopeFactory>())); // 直接添加过滤器实例(构造函数已无参数) config.UseFilter(new HangfireSessionFilter()); });
3. 优化ServiceJobActivatorScope的Resolve方法
你的自定义Activator逻辑没问题,但可以简化Resolve方法(两种方式都支持从当前Scope获取服务):
public class ServiceJobActivatorScope : JobActivatorScope { readonly IServiceScope _serviceScope; public ServiceJobActivatorScope(IServiceScope serviceScope) { _serviceScope = serviceScope ?? throw new ArgumentNullException(nameof(serviceScope)); } public override object Resolve(Type type) { // 直接从当前Scope的服务提供者获取实例,与过滤器上下文拿到的是同一个 return _serviceScope.ServiceProvider.GetService(type); } }
原理说明
- Hangfire执行每个Job时,会通过你自定义的
ServiceJobActivator创建独立的ServiceJobActivatorScope(对应一个Scoped服务容器)。 - 过滤器的
OnPerforming/OnPerformed方法可以通过上下文的ServiceProvider访问到当前Job的Scope容器,从而拿到和Job实例中注入的同一个IUnitofWork实例。 - 之前的错误是在Startup阶段就从根容器获取Scoped服务,导致过滤器的IUnitofWork与Job的Scope完全无关,自然无法共享。
内容的提问来源于stack exchange,提问作者Angelo Fuller
相关产品推荐
相关产品推荐

