繁体   English   中英

如何从 autofac 容器解析依赖项(在嵌套的 LifetimeScope 中注册)

[英]How can a dependency (registered in nested LifetimeScope) be resolved from autofac container

有什么方法可以解决容器的依赖关系(实际上是在嵌套的 LifetimeScope 中注册的,而不是在容器中)?

实际执行说明:

我有包含当前用户基本信息的ApplicationContext类(在其构造函数中注入了IServiceProvider )。 它首先从serviceProvider解析IHttpContextAccessor ,然后从httpContextAccessor.HttpContext提取用户信息。 ApplicationContext类被注入到所有存储库/服务中。

但是,在一些静态类中,我从静态 IoC 类(包装在其中的 autofac 容器)解析ApplicationContext类。 我认为这是唯一的解决方案,因为我无法注入静态构造函数。

我正在实现事件总线,我EventBusContext创建了EventBusContext类,该类从事件数据接收用户信息。

ApplicationContext类尝试从IServiceProvider解析EventBusContext在它获取HttpContext为 null 时从中提取用户信息(这意味着此执行不是从 Http Request 开始)。

一旦EventBus类接收到来自 RabbitMQ 的事件,它就会创建EventBusConext类,将用户信息添加到其中并动态注册到新创建的嵌套LifetimeScope然后解析EventHandler类并调用 Handle 方法(通过反射)。

一切正常! 仅当EventHandler使用从静态IoC类解析ApplicationContext类的任何类时才会出现此问题,因为静态IoC类在内部尝试从 autofac 容器(包装在其中)解析EventBusContext但它未能这样做。

我将专注于开始的最初问题:

有什么方法可以解决容器的依赖关系(实际上是在嵌套的 LifetimeScope 中注册的,而不是在容器中)?

最简洁的答案是不。 如果在子作用域中注册/添加了某些内容,则父作用域无法知道它。

Autofac 范围是分层的。有很多关于此的文档,包括一个图表来说明这一点。

试图将其归结为“规则”,我们可以说:

  • 注册“规则”:
    • 您可以将东西注册到根容器中。
    • 创建子生命周期范围时,您可以添加仅针对该范围存在的新注册。
  • 决议“规则”:
    • 当您解析服务时,它只会知道您正在解析的生命周期范围内注册的内容以及任何父项。
    • 如果您解析单例,它将始终从根生命周期范围解析,包括其所有依赖项。
    • 子作用域了解父作用域。
    • 父作用域不包含引用或“知道”子作用域。

这非常简化,但足以说明这一点。

如果您将内容动态添加到子生命周期范围内,您将只能在该子生命周期范围以及您从那里创建的任何子范围内访问它们。

var builder = new ContainerBuilder();
builder.RegisterType<A>();
var container = builder.Build();

// This will work (though it's recommended you avoid resolving things
// from containers because it can lead to memory leaks).
// https://autofac.readthedocs.io/en/latest/lifetime/index.html
container.Resolve<A>();

// This will NOT work. The container doesn't have B in it.
container.Resolve<B>();

using(var scope1 = container.BeginLifetimeScope(b => b.RegisterType<B>())
{
  // This will work. The child scope knows about parent registrations.
  scope1.Resolve<A>();

  // This will also work. The registration was added to the scope.
  scope1.Resolve<B>();

  // This will STILL NOT WORK. The parent does NOT know about child scopes.
  container.Resolve<B>();

  using(var scope2 = scope1.BeginLifetimeScope())
  {
    // These will work. The child scope knows about parent registrations.
    scope2.Resolve<A>();
    scope2.Resolve<B>();

    // This will STILL NOT WORK.
    container.Resolve<B>();
  }
}

没有黑客或解决方法。 它是故意分层的。

如果您需要访问请求级别的项目(或者需要动态注册在子生命周期范围内的事物),那么获取它们唯一方法是从该子生命周期范围或嵌套子项中解析。

更具体的目标:

从实现描述中,您有一些东西故意在请求之外运行并从根容器解析(同样,这不是一个好主意,但它就是这样)。 如果这些东西突然需要通过请求即时注册的项目,那么您基本上有两种选择,这两种选择都是“您需要更改架构/设计”。

  1. 将在“请求外”运行的所有项目切换到“请求内”运行,以便它们可以访问动态注册的事物。
  2. 更改方法签名或其他任何内容,以便动态注册的事物不是“请求外部”项的依赖项 - 使这些动态事物作为方法参数传入。

实际上,提供一个完全更新的设计或“工作代码”来说明这些事情中的任何一个,与其说是对问题的回答,不如说是一种咨询工作。 然而不幸的是,获取每个请求数据的解决方案意味着您需要更改您的设计。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM