混合 HangFire 和 IoC 容器和多租户

问题描述

我正在绞尽脑汁想了解如何解决 IoC 容器和 Hangfire 周围的各种限制。我对 IoC 使用还很陌生,因为我继承了一个外包应用程序,我不确定它是否设计得很好。

所以我们有一个多租户应用程序,它使用内部 API 来处理业务逻辑。 API 使用基本身份验证针对主租户数据库进行身份验证。流程看起来像这样。

  1. 主应用程序通过代理发送调用 -> 内部 API。
  2. 内部 API 使用自定义 HttpModule 处理身份验证,并设置声明。
  3. 实体框架构造函数使用声明来识别租户并连接数据库
  4. 使用 IRepositoryAsync 和 UnitOfWork 抽象将 EF 实例实例化为依赖项。

例如,一个服务类看起来像这样:

public class EmailService : IEmailService(ICompanyService companyService,IRepositoryAsync<Entity.Employee>...)

这适用于当前用例。但是,我正在尝试将需要在特定上下文中运行的 Hangfire 作业添加到组合中。 Hangfire 作业必须是静态的,或者它们可以是一个实例方法,但会在其自己的单独上下文中初始化该类。如何以正确的顺序实例化事物以在 Hangfire 上下文中运行?

  1. HangFire 实例作业位于上面的 EmailService 内。因此它会收到必要的依赖项。
  2. 但是,依赖项需要具有声明的活动用户会话。
  3. 如果我尝试在方法中创建用户身份,则实例化为时已晚,因为组合依赖项已经需要它。
  4. 唯一可用的上下文是在方法之外提供的环境上下文。

所以我尝试使用 HangFire 过滤器来实现,它会解释传递给 Hangfire 方法的租户 ID,并创建一个临时用户身份,例如:

    public class APIContextHelper
    {
        private static AsyncLocal<TemporaryIdentity> _TemporaryIdentity = new AsyncLocal<TemporaryIdentity>();

        public class TemporaryIdentity : Idisposable
        {
            protected readonly IPrincipal _oldPrincipal;
            protected bool _disposed;

            public TemporaryIdentity(IPrincipal principal)
            {
                _TemporaryIdentity.Value = this;
            }

            public void dispose() { this.dispose(true); GC.SuppressFinalize(this); }

            protected virtual void dispose(bool disposing)
            {
                if (!this._disposed)
                {
                    this._disposed = true;
                    _TemporaryIdentity.Value = null;
                }
            }
        }

        public static Idisposable UseTemporaryIdentity(string BureauID)
        {
            if (_TemporaryIdentity.Value != null) throw new ApplicationException("Cannot create nested temporary identity.");

            var principal = BasicAuthHttpModule.GeneratePrincipal(BureauID);
            var tempIdentity = new TemporaryIdentity(principal);
            return tempIdentity;
        }

        public static void disposeTemporaryIdentity()
        {
            if (_TemporaryIdentity.Value == null) throw new ApplicationException("Temporary identity is not available to be disposed.");

            _TemporaryIdentity.Value.dispose();
        }
    }

这是过滤器:

    public class UseIdentityFormatStringAttribute : JobFilterattribute,IServerFilter
    {
        private Idisposable _tempIdentity;
        private string _format;

        public UseIdentityFormatStringAttribute(string format)
        {
            _format = format;
        }

        public void OnPerformed(PerformedContext filterContext)
        {
            _tempIdentity.dispose();
        }

        public void OnPerforming(PerformingContext filterContext)
        {
            var bureauID = string.Format(_format,filterContext.BackgroundJob.Job.Args.ToArray());
            _tempIdentity = PhoenixAPIContext.UseTemporaryIdentity(bureauID);
        }
    }

这有效......主要是。它工作了一段时间然后开始失败,因为环境上下文以某种方式在两个 Hangfire 实例之间共享并且没有被正确丢弃。所以一堆作业失败了,因为他们没有清除以前的临时身份。我怀疑问题是 AsyncLocal 和环境上下文的某种错误组合,但对我来说这已经变得难以推理了。

我知道,如果我只是在需要时更新连接、拨打服务电话并完成工作,我可以在五分钟内解决这个问题。但是因为它使用 IoC,所有的需求都必须被注入,并且因为它使用 HangFire 租户信息必须由环境上下文提供,并且因为它使用 await/async,任何环境上下文都必须小心管理。

是否有任何简单的解决方案,或者设计是否存在根本问题?

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...