4

我正在創建一個HttpClient的實例,用於我的Web應用程序正在與之通信的每個不同的API。使用依賴注入管理HttpClient的多個實例

我想使用依賴注入SimpleInjectorHttpClient注入業務類。例如,我有ITwitterBusinessIInstagramBusiness,並且他們兩人都在其構造函數中接受HttpClient

當使用依賴注入來註冊同一類型的多個對象時,最佳實踐是什麼?

我很確定問題的一部分可能是我的設計,但這裏有一些想法。

我的第一個想法是在DI註冊

container.Register<ITwitterBusiness>(() => new TwitterBusiness(httpClientTwitter)); 

似乎很簡單的使用委託,但我不知道這種方法有任何不良的副作用,例如通過使SimpleInjector運行速度較慢或者如果我打破了一些設計模式。

我的第二個想法是使用基於上下文注入http://simpleinjector.readthedocs.io/en/latest/advanced.html#context-based-injection

我相信這會讓我注入了一定HttpClient的實例,以某一類。仍然不完全確定這是如何工作的。

我很好奇,如果我可以純粹的設計解決這個問題。例如通過創建虛擬類。我只是沒有找到任何好的例子,但如果我理解正確的話,我可以創建虛擬類,如HttpClientTwitter,它繼承HttpClient,這樣我就可以擺脫模糊的註冊。

謝謝!

回答

3

我的第一個想法是在DI註冊中使用委託。似乎很簡單,但我不知道這種方法是否有任何不良的副作用,例如通過使SimpleInjector運行速度較慢或如果我打破某種設計模式。

如果類型中有任何需要連接的應用程序組件,建議使用自動佈線(與註冊委託相反)。自動佈線簡化了註冊,並允許簡單注射器分析對象圖。你的情況似乎都沒有關係。 HttpClient不是應用程序組件,而是基礎結構類型。似乎沒有其他依賴關係,因此註冊代理不會造成任何可維護性問題。

與使用自動佈線相比,委託註冊較慢,Simple Injector無法使用代表進行優化。然而,當你這樣做的時候,你不會注意到任何性能上的不同。這不是你應該擔心的。

我的第二個想法是使用基於上下文的注入。我相信這將允許我將某個HttpClient實例注入某個類。仍然不完全確定這是如何工作的。

您可以根據上下文進行不同的註冊。例如:

var httpClientTwitterRegistration = Lifestyle.Transient.CreateRegistration<HttpClient>(
    () => new HttpClient("https://twitter"), 
    container); 

container.RegisterConditional(typeof(HttpClient), httpClientTwitterRegistration, 
    c => c.Consumer.ImplementationType == typeof(TwitterBusiness)); 

var httpClientInstagramRegistration = Lifestyle.Transient.CreateRegistration<HttpClient>(
    () => new HttpClient("https://instagram"), 
    container); 

container.RegisterConditional(typeof(HttpClient), httpClientInstagramRegistration, 
    c => c.Consumer.ImplementationType == typeof(InstagramBusiness)); 

我很好奇,如果我能解決這個純粹的設計

通過注入HttpClientTwitterBusiness類,你得到的靈活性虛假的安全感。你似乎可以實現兩個交換實現,但由於HttpClient是一個具體類型,所以更改實現是沒有意義的。由於TwitterBusiness直接與HttpClient進行通信,因此應將其作爲實施細節。換句話說,在TwitterBusiness內移動HttpContext的創建。您需要配置的任何參數(可能是url)都可以注入到TwitterBusiness中。這種方式TwitterBusiness是在完全控制HttpClient的創建和處置,你注入唯一有趣的變化(網址)。

+1

謝謝史蒂文。我忘了提及所有的HttpClient實例都是單例,所以Twitter HttpClient實例將在應用程序的生命週期中重用。我總是傾向於避免靜態變量,但我想我可以將它作爲TwitterBusiness中的一個靜態變量,並且只在構造函數中爲null時初始化它。你怎麼看?對於單元測試,我可以將HttpMessageHandler傳遞給構造函數。 – raRaRa

+0

@raRaRa你甚至可以註冊你的TwitterBusiness作爲單身人士,以防它無狀態(通常應該)。這意味着你的httpclient仍然可以是一個實例變量,但我不認爲HttpClient是線程安全的。因此,在每一個內部創建它都是最安全的。 – Steven

+0

它是線程安全的,應儘可能重用。這就是爲什麼我希望它是單身人士。否則,我只需在TwitterBusiness上按需創建HttpClient的實例。但你絕對是對的,TwitterBusiness可以註冊爲單身人士。我會考慮通過並嘗試提出一個決定。謝謝您的幫助! :) – raRaRa