使用依赖注入管理多个 HttpClient 实例
Posted
技术标签:
【中文标题】使用依赖注入管理多个 HttpClient 实例【英文标题】:Managing multiple instances of HttpClient using Dependency Injection 【发布时间】:2016-11-20 13:27:54 【问题描述】:我正在为我的 Web 应用程序与之通信的每个不同 API 创建一个 HttpClient
实例。
我想使用 SimpleInjector 的依赖注入将 HttpClient
注入业务类。例如,我有ITwitterBusiness
和IInstagramBusiness
,它们都在构造函数中接受HttpClient
。
在使用依赖注入注册多个相同类型的对象时,最佳实践是什么?
我很确定问题的一部分可能是我的设计,但这里有一些想法。
我的第一个想法是在 DI 注册中使用委托
container.Register<ITwitterBusiness>(() => new TwitterBusiness(httpClientTwitter));
看起来很简单,但我不知道这种方法是否有任何不良副作用,例如使 SimpleInjector 运行速度变慢,或者我是否破坏了某些设计模式。
我的第二个想法是使用基于上下文的注入 http://simpleinjector.readthedocs.io/en/latest/advanced.html#context-based-injection
我相信这将允许我将某个 HttpClient 实例注入某个类。仍然不确定这是如何工作的。
我很好奇我是否可以完全通过设计来解决这个问题。例如通过创建虚拟类。我只是没有找到任何好的例子,但如果我理解正确,那么我可以创建继承HttpClient
的虚拟类,例如HttpClientTwitter
,这样我就可以摆脱模棱两可的注册。
谢谢!
【问题讨论】:
【参考方案1】:我的第一个想法是在 DI 注册中使用委托。看起来很简单,但我不知道这种方法是否有任何不良副作用,例如使 SimpleInjector 运行速度变慢,或者我是否破坏了某些设计模式。
如果类型有任何需要连接的应用程序组件,建议使用自动连接(与注册委托相反)。自动连接简化了注册并允许 Simple Injector 分析对象图。在您的情况下,两者似乎都无关紧要。 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));
我很好奇我是否可以完全通过设计来解决这个问题
通过将HttpClient
注入TwitterBusiness
类,您会得到错误的灵活性。您似乎可以进行两种交换实现,但由于 HttpClient
是一种具体类型,因此更改实现毫无意义。由于TwitterBusiness
直接与HttpClient
通信,因此应该将其作为实现细节。换句话说,将HttpClient
的创建移动到TwitterBusiness
中。您需要配置的任何参数(可能是 url)都可以注入TwitterBusiness
。这样TwitterBusiness
就可以完全控制HttpClient
的创建和处置,并且您注入唯一感兴趣的内容(网址)。
【讨论】:
谢谢史蒂文。我忘了提到所有的 HttpClient 实例都是单例的,所以 Twitter HttpClient 实例将在应用程序的生命周期中重复使用。我总是倾向于避免使用静态变量,但我想我可以将它作为 TwitterBusiness 中的静态变量,并且如果它在构造函数中为空,则只初始化一次。你怎么看?对于单元测试,我可以将 HttpMessageHandler 传递给构造函数。 @raRaRa 你甚至可以将你的 TwitterBusiness 注册为单例,以防它是无状态的(它通常应该这样做)。这意味着您的 httpclient 仍然可以是实例变量,但我不认为 HttpClient 是线程安全的。所以在每个 mrthod 中创建它是最安全的。 它是线程安全的,应该尽可能地重复使用。这就是为什么我希望它是单例的。否则我只会在 TwitterBusiness 中按需创建 HttpClient 实例。但你绝对是对的,TwitterBusiness 可以注册为单例。我会考虑清楚并尝试做出决定。谢谢您的帮助! :) 似乎单身最好:aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong以上是关于使用依赖注入管理多个 HttpClient 实例的主要内容,如果未能解决你的问题,请参考以下文章
ASP.NET Core依赖注入高级玩法——如何注入多个服务实现类
Angular 2 中的依赖注入在使用内联注入器和构造器注入时创建多个实例
使用特定的 HttpMessageHandler 注入单实例 HttpClient
如何将 RateLimiter 的 HttpClient DelegatingHandler 与依赖注入一起使用?