Hangfire 使用用户上下文运行后台作业

标签 hangfire

我有一个应用程序,具有 Multi-Tenancy 。我想在用户上下文下创建后台作业,但我找不到实现它的好方法。
我将解释一下我的架构。我正在使用包含 UserID 的接口(interface) ICurrentUser。在 Startup 类中,我在 IoC 中注册了实现 ICurrentUser 的类 WebUser,该类获取 HttpContext 并从声明中提取用户详细信息。

我正在执行后台作业,并且 ICurrentUser.UserID 按预期为空,因为hangfire 没有任何httpcontext。

我通过使用接受 ICurrentUser 作为第一个参数的方法创建我的后台任务来解决这个问题,然后在方法体内,
我为 UnitOfWork(和 AppServices)设置了“CurrentUser”并开始执行任务,这种方法的问题是我必须对每个后台任务重复此代码并将 CurrentUser 传递给它。

我的问题如何才能实现下一件事。或者,也许您可​​以建议其他解决方案。

  • 如何将我的 CurrentUser 传递给 JobActivator,以便在解决所有服务之前设置用户上下文。

  • 例如,它可能看起来像这样:
    BackgroundJob.Enqueue<MySvc>(UserContext, mysvc=>mysvc.Run());
    

    我阅读了资料,并没有找到任何扩展点来实现这一点。

    任何帮助是极大的赞赏。

    最佳答案

    最后,我完成了与@jbl 建议的几乎相同的解决方案。
    我创建了一个过滤器,将我当前的用户存储到作业参数中。

    public class BackgroundJobFilter : JobFilterAttribute, IClientFilter, IApplyStateFilter
    {
        private readonly IServiceProvider _serviceProvider;
    
        public BackgroundJobFilter(IServiceProvider serviceProvider)
        {
            _serviceProvider = serviceProvider;
        }
    
        public void OnCreating(CreatingContext filterContext)
        {
            var currentUser = _serviceProvider.GetRequiredService<ICurrentUser>();
            filterContext.SetJobParameter(nameof(ICurrentUser), currentUser);
        }
    }
    

    然后将过滤器添加到 Hangfire

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        GlobalConfiguration.Configuration.UseFilter(new BackgroundJobFilter(app.ApplicationServices));
    }
    

    然后我替换了当前的工作激活器

        internal class ServiceJobActivatorScope : JobActivatorScope
        {
            private readonly IServiceScope _serviceScope;
    
            public ServiceJobActivatorScope([NotNull] IServiceScope serviceScope)
            {
                if (serviceScope == null)
                    throw new ArgumentNullException(nameof(serviceScope));
    
                _serviceScope = serviceScope;
            }
    
            public override object Resolve(Type type)
            {
                return ActivatorUtilities.GetServiceOrCreateInstance(_serviceScope.ServiceProvider, type);
            }
    
            public override void DisposeScope()
            {
                _serviceScope.Dispose();
            }
        }
    

    最后,设置当前用户详细信息(在运行任务时为空)

      public class CustomJobActivator : JobActivator
        {
            private readonly IServiceScopeFactory _serviceScopeFactory;
            private readonly IMapper _objectMapper;
    
    
            public CustomJobActivator([NotNull] IServiceScopeFactory serviceScopeFactory, IMapper objectMapper)
            {
                if (serviceScopeFactory == null)
                    throw new ArgumentNullException(nameof(serviceScopeFactory));
    
                _serviceScopeFactory = serviceScopeFactory;
                _objectMapper = objectMapper;
            }
    
            public override JobActivatorScope BeginScope(JobActivatorContext context)
            {
                var user = context.GetJobParameter<WebUser>(nameof(ICurrentUser));
    
                var serviceScope = _serviceScopeFactory.CreateScope();
    
                var currentUser = serviceScope.ServiceProvider.GetRequiredService<ICurrentUser>();
                //Copy value from user to currentUser
                _objectMapper.Map(user, currentUser);
    
                return new ServiceJobActivatorScope(serviceScope);
            }
        }
    

    然后替换容器中已有的 JobActivator

    services.Replace(new ServiceDescriptor(typeof(JobActivator), typeof(CustomJobActivator), ServiceLifetime.Scoped));
    

    之后,当服务开始从此范围解析时,当我使用 ICurrentUser 正常工作时,它们将获得用户上下文和 DbContext 和其他地方的所有过滤器。

    关于Hangfire 使用用户上下文运行后台作业,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58101626/

    相关文章:

    hangfire - 将多个hangfire实例与单个数据库一起使用

    c# - 在asp.net core c#中使用hangfire时多次构造单例服务

    hangfire - 使用 Hangfire(共享任务/对象)的多个服务实例,是否可能?

    c# - Hangfire 交易流程(工作单元)

    c# - Hangfire 单实例重复作业

    c# - 如何为 Hangfire 的 mySQL 数据库设置 'connectionString'?

    c# - 如何在所有 Azure 可用实例上分派(dispatch) Hangfire 作业?

    c# - 在 ASP.NET CORE Web 应用程序中从 appsettings.json 加载 Hangfire 配置

    asp.net-mvc - Autofac (+MVC + EF + SignalR + Hangfire) 生命周期范围

    c# - 尽管任务在数据库中,但 Hangfire 不运行任务