如何解决混合 HangFire 和 IoC 容器和多租户
我正在绞尽脑汁想了解如何解决 IoC 容器和 Hangfire 周围的各种限制。我对 IoC 使用还很陌生,因为我继承了一个外包应用程序,我不确定它是否设计得很好。
所以我们有一个多租户应用程序,它使用内部 API 来处理业务逻辑。 API 使用基本身份验证针对主租户数据库进行身份验证。流程看起来像这样。
- 主应用程序通过代理发送调用 -> 内部 API。
- 内部 API 使用自定义 HttpModule 处理身份验证,并设置声明。
- 实体框架构造函数使用声明来识别租户并连接数据库。
- 使用 IRepositoryAsync 和 UnitOfWork 抽象将 EF 实例实例化为依赖项。
例如,一个服务类看起来像这样:
public class EmailService : IEmailService(ICompanyService companyService,IRepositoryAsync<Entity.Employee>...)
这适用于当前用例。但是,我正在尝试将需要在特定上下文中运行的 Hangfire 作业添加到组合中。 Hangfire 作业必须是静态的,或者它们可以是一个实例方法,但会在其自己的单独上下文中初始化该类。如何以正确的顺序实例化事物以在 Hangfire 上下文中运行?
- HangFire 实例作业位于上面的
EmailService
内。因此它会收到必要的依赖项。 - 但是,依赖项需要具有声明的活动用户会话。
- 如果我尝试在方法中创建用户身份,则实例化为时已晚,因为组合依赖项已经需要它。
- 唯一可用的上下文是在方法之外提供的环境上下文。
所以我尝试使用 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 举报,一经查实,本站将立刻删除。