1

後,我有一種情況,我有的WebAPI的客戶需要在它的構造基礎URL和配置管理器類,從web.config中讀取配置。簡單的噴油器註冊調用getInstance方法

interface IConfigManager 
{ 
    string baseurl {get;} 
} 
class ConfigManager:IConfigManager 
{ 
public string baseurl => system.configuration.ConfigruationManager.AppSettings["URL"]; 
} 

和我有調用網頁API

interface IApiClient 
{ 
List<Products> GetProducts(string addresssufix); 
} 

public class ApiClient:IApiClient 
{ 
public ApiClient(string baseUrl) 
{ 
//---- 
} 
List<Products> GetProducts(string addresssufix) 
{ 
//.... 
} 
} 

,所以我需要地址在APiClient

在簡單注射器而組件的註冊客戶端類。

container.Register<IConfigManager, ConfigManager>(); 
var config= container.GetInstance<IConfigManager>(); 

container.Register<IApiClient<(()=> new ApiClient(config.baseurl)); 

,但它說,調用的GetInstance

+0

相關:https://stackoverflow.com/questions/27288520/how-to-do-a-registration-in-simple-injector-after-a-getinstance-call-alternate – Steven

回答

3

簡單的注射器塊第一次調用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。換句話說,只有在你確定不會發生錯誤配置的情況下,才應該在極少數情況下使用此構造。

+0

是否有任何方法可以從中獲得IConfigmanager實例? –

+0

@Imranbutt:我不明白你的問題。你能改述一下嗎? – Steven

+0

意味着還有其他方法嗎? –

1

傳遞依賴的對象ApiClient後我不能註冊,而不是隻是它的性質。如果該對象具有太多的ApiClient不感興趣的屬性,請執行界面分離。

container.Register<IConfigManager, ConfigManager>(); 
container.Register<IApiClient, ApiClient>(); 

public ApiClient(IConfigManager configManager) 
{ 
    this.baseurl = configManager.baseurl; 
} 

container.GetInstance<ApiClient>(); 
+0

偉大的解決方案,但如果我在單獨的Nuget包中有Api客戶端...它是否也能工作? –

+0

那麼你有組件之間的依賴關係(和你的情況下的NuGet包)。 –

相關問題