0

ConfigureServices()引導我的應用程序期間,我註冊了大多數瞬態和範圍類型的隨.NET Framework附帶的依賴注入框架。但是,我確實有一種類型被註冊爲單例是我的InProcessBus(我正在使用CQRS樣式的體系結構)。IServiceProvider.GetSingleton在Asp.Net核心解析爲空DI

services.AddSingleton<InProcessBus>(new InProcessBus()); 
...   
services.AddSingleton<ICommandSender>(y => y.GetService<InProcessBus>()); 
services.AddSingleton<IEventPublisher>(y => y.GetService<InProcessBus>()); 

正如你所看到的,我正在使用實現工廠函數來實現將在API控制器中使用的實際類型。真正奇怪的是,當控制器加載並且運行時嘗試構造器注入ICommandSender時,它無法解析並報告錯誤。

如果我檢查serviceCollection我可以看到,implementationFactory根據ImplementationInstance屬性下的類型正確註冊。

StartupConfigureServices()方法末尾深究並直接解決類型,確認容器正在解析null

ServiceLocator.GetService<ICommandSender>() // Is Null 

爲什麼一個ImplementationFactory方法針對明確存在於容器中的單例在運行時不能解析?

+0

這很奇怪。儘管你可能想避免使用'y.GetService ()'並使用'y.GetRequiredService()',如果它不能被解析,將拋出一個異常,而不是返回null。儘管這可能無法解決您的問題。還有更多嗎?你也不能在'ConfigureServices'裏面解決它,那時容器還沒有建成。 Earlierst點您可以通過'Configure'方法解析服務(如果您使用模板附帶的標準Startup.cs) – Tseng

+0

您確定要使用內置容器嗎? CQRS架構風格非常強大,因爲它們使得使用裝飾器應用橫切關注變得非常容易。使用內置容器來應用通用裝飾器是不可能的。 – Steven

+0

@Tseng,感謝GetRequiredService提示,顯式異常比null更好。通常無法解決是的,但我使用BuildServiceProvider()來構建我自己的提供程序,以便在出現問題時使用內聯進行測試... –

回答

3

我發現了什麼錯誤,並認爲我會在這裏發佈它,因爲它有一個重要的教訓。

簡短的回答:

推遲serviceCollection.BuildServiceProvider()到已註冊爲其他所有的單實例後,將不能夠解決這些問題。

長的答案:

這個問題實際上一點關係都沒有用asp核心DI容器(也八九不離十)。問題出在我打電話給實例上的BuildServiceProvider的時機爲我提供了一個IServiceProvider

在我的實現中,我實現了一個ServiceLocator模式,它包裝了隨核提供的DI框架,以便在其他架構層中不引入額外的依賴關係。當我建立我的基於IServiceContainer定位器我立即解決ServiceProvider

public ServiceLocator(
     IServiceCollection serviceCollection) 
    { 
     _serviceCollection = serviceCollection; 
     _serviceProvider = _serviceCollection.BuildServiceProvider(); 
    } 

而這正是問題的躡手躡腳。當ServiceProvider得到明顯創造了TransientsScoped情況不要緊的時間。 但是對於有管理生命週期的單身人士,它確實是。在所有註冊之後,您需要推遲創建您的ServiceProviders

從我的問題ServiceLocator是在片段之前構建的,這意味着執行implementationFactory函數時,Singleton實例不可訪問ServiceProvider

通過推遲創建ServiceProvider到第一次,我的應用程序在運行時解決了我的一個自定義類型,解決了這個問題。

+0

這種方法可能會遇到其他問題(忽略服務定位符是反模式的事實並且違背了DI/IoC的全部目的):系統中現在有兩個容器,一個是ASP.NET Core之前創建的容器調用'Configure'和你爲反模式定位器創建的一個,這對於使用ASP.NET Core IoC的服務和使用你的服務定位器的服務將會有不同的實例,這將是一個範圍化服務(DbContext)的問題,調用' SaveChanges()'例如不能保護來自其他上下文的更改,並且失去工作單元優勢 – Tseng

+0

也可以詳細說明「_pattern,它包裝隨核心附帶的DI框架,以便不引入額外的依賴項在我的其他建築layers_「?你不需要其他層的任何其他依賴到'Microsoft.Extensions.DependencyInjection'。您只需要在Web應用程序中(在構建根中構建對象圖的位置)。從架構的角度來看,你的方法似乎非常錯誤,並且它創建了一個很難的依賴關係,並且變得很難/不可能進行單元測試 – Tseng