微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

混合 HangFire 和 IoC 容器和多租户

如何解决混合 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 举报,一经查实,本站将立刻删除。