使用依赖注入管理多个 HttpClient 实例

Posted

技术标签:

【中文标题】使用依赖注入管理多个 HttpClient 实例【英文标题】:Managing multiple instances of HttpClient using Dependency Injection 【发布时间】:2016-11-20 13:27:54 【问题描述】:

我正在为我的 Web 应用程序与之通信的每个不同 API 创建一个 HttpClient 实例。

我想使用 SimpleInjector 的依赖注入将 HttpClient 注入业务类。例如,我有ITwitterBusinessIInstagramBusiness,它们都在构造函数中接受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 与依赖注入一起使用?

依赖注入:HttpClient 还是 HttpClientFactory?

当 API 关闭时,Xamarin 表单依赖注入 HttpClient 超时不起作用