簡單的注射器塊第一次調用GetInstance
強制註冊和解析之間嚴格登記後Register
任何電話。這種設計可以防止奇怪,難以調試和難以驗證的行爲,如文檔中更詳細地解釋here。
但是就像你要登記階段從你開始從容器解決分離相,你應該閱讀的配置值時一樣。只有在應用程序啓動時,才能在註冊階段之前或期間加載配置值。延遲配置值的讀取會導致應用程序變得脆弱,並迫使您瀏覽整個應用程序以確定應用程序是否配置正確,但通過在啓動時加載配置可以輕鬆防止這種情況應用程序快速失敗)。
這意味着,在你的情況下,抽象爲IConfigManager
沒什麼意義,因爲它的唯一目標是延遲從應用設置中加載基本URL,同樣,這應該直接在啓動(如果該值缺失或格式錯誤,最好應該失敗)。
考慮到這一點,我想提出以下改進和簡化您的設計:
var container = new Container();
string baseUrl = System.Configuration.ConfigruationManager.AppSettings["URL"];
if (string.IsNullOrEmpty(baseUrl))
throw new ConfigurationErrorsException("appSettings/URL is missing.");
container.RegisterSingleton<IApiClient>(new ApiClient(baseUrl));
見的配置如何,直接在啓動時讀取並立即值是否存在檢查。之後baseUrl
直接在ApiClient
構造函數中使用。另請注意,ApiClient
已註冊爲Singleton
。我在這裏假設ApiClient
是無狀態和不可變的(這是一個很好的做法)。您通過讓你ApiClient
做了正確的事情
注取決於string baseUrl
的配置價值,而不是注入IConfigManager
。使用ConfigManager
作爲應用程序代碼中的抽象代碼通常是有問題的。這種配置抽象通常會在應用程序的生命週期中無限期地增長,因爲每次將新的配置值添加到配置時,都需要更新此抽象(及其實現和可能的假實現)。這種抽象的消費者通常只會依賴一個或幾個配置值,但絕不會。這表示違反了Interface Segregation Principle。問題在於測試該接口的消費者變得更加困難,因爲您通常希望確保它們使用正確的配置值。另一個問題是,通過定義這樣的消費者(其類型名稱及其具有所需依賴關係的構造函數),不可能看到實際需要哪些配置值。
當您讓消費者直接依賴他們所需的配置值時,所有這些問題都會完全消失。但是再次,這甚至不需要首先獲得這種抽象。
請注意,雖然寄存器決心寄存器是不允許的,你就能夠做到,而不是執行以下操作:
container.Register<IConfigManager, ConfigManager>();
container.Register<IApiClient>(() =>
new ApiClient(container.GetInstance<IConfigManager>().baseurl));
這到底是怎麼回事是GetInstance<IConfigManager>
被稱爲委託進行的一部分IApiClient
。這將起作用,因爲在這種情況下,GetInstance<IConfigManager>()
在解析IApiClient
時被調用,因此在註冊過程之後被調用。換句話說,解決IConfigManager
被延遲。
雖然這是個大警告:這種做法通常不建議。如前所述,當涉及配置值時,我們不希望延遲加載它們。但即使在其他情況下,我們通常也不想這樣做,因爲這種構造盲目地使用簡單注射器的驗證和診斷系統。由於Simple Injector使用靜態可用信息(如構造函數參數)來分析對象圖,因此此類動態調用將禁止簡單注入器查找常見問題,如Lifestyle Mismatches。換句話說,只有在你確定不會發生錯誤配置的情況下,才應該在極少數情況下使用此構造。
相關:https://stackoverflow.com/questions/27288520/how-to-do-a-registration-in-simple-injector-after-a-getinstance-call-alternate – Steven