簡體   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