依赖注入:HttpClient 还是 HttpClientFactory?

Posted

技术标签:

【中文标题】依赖注入:HttpClient 还是 HttpClientFactory?【英文标题】:Dependency injection: HttpClient or HttpClientFactory? 【发布时间】:2019-12-11 06:44:17 【问题描述】:

我到处都可以看到在 DI 中创建客户端(基本、命名、键入)的三种主要方法,但我找不到注入 IHttpClientFactoryHttpClient(两者都可能)的方法。

Q1:请问注入IHttpClientFactoryHttpClient有什么区别?

Q2:如果IHttpClientFactory被注入,每次调用我应该使用factory.CreateClient()吗?

【问题讨论】:

当我在 startup.cs 中设置 services.AddHttpClient(c => c.BaseAddress = new Uri("https://api.github.com/"); ); 并将 HttpClient 注入我的服务时,它应该使用与注入 IHttpClientFactory.CreateClient() 相同的客户端,对吧? 【参考方案1】:

总结

HttpClient 只能注入到 Typed 客户端 其他用途需要IHttpClientFactory 在这两种情况下,HttpClientMessageHandler 的生命周期都由框架管理,因此您不必担心(错误地)处置 HttpClients

示例

为了直接注入HttpClient,你需要注册一个特定的Typed服务来接收客户端:

services.AddHttpClient<GithubClient>(c => c.BaseAddress = new System.Uri("https://api.github.com"));

现在我们可以将其注入到 typed GithubClient

public class GithubClient

    public GithubClient(HttpClient client)
    
        // client.BaseAddress is "https://api.github.com"
    

您不能在AnotherClient 中注入HttpClient,因为它没有输入AnotherClient

public class AnotherClient

    public AnotherClient(HttpClient client)
    
        // InvalidOperationException, can't resolve HttpClient 
    

但是,您可以: 1. 注入IHttpClientFactory并调用CreateClient()。此客户端将 BaseAddress 设置为 null。 2. 或者将AnotherClient 配置为不同类型的客户端,例如使用不同的BaseAdress

更新

根据您的评论,您正在注册一个命名客户。它仍然是从 IHttpClientFactory.CreateClient() 方法解决的,但您需要传递客户端的“名称”

注册

services.AddHttpClient("githubClient", c => c.BaseAddress = new System.Uri("https://api.github.com"));

用法

// note that we inject IHttpClientFactory
public HomeController(IHttpClientFactory factory)

    this.defaultClient = factory.CreateClient(); // BaseAddress: null
    this.namedClient = factory.CreateClient("githubClient"); // BaseAddress: "https://api.github.com"

【讨论】:

是的对不起,我的AddHttpClient的第一个参数是string.Empty 根据您的评论更新了答案并澄清了示例(我希望:D) 如果我在ActionFilterAttribute 中使用HttpClient 怎么办?在这种情况下,您需要使用context.HttpContext.RequestServices.GetService 来获取服务而不是构造函数。【参考方案2】:

遗憾的是,我无法发表评论,只能发布答案。因此,我建议您查看以下链接:

https://docs.microsoft.com/en-us/dotnet/architecture/microservices/implement-resilient-applications/use-httpclientfactory-to-implement-resilient-http-requests

https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/

关于您的问题,或多或少可以归结为:

Q1 -> IHttpClientFactory 处理 HttpClient 实例的连接池,如果 HttpClient 使用错误,这将帮助您解决链接中描述的加载和处理问题。

Q2 -> 是的,您应该根据微软文档使用 factory.create 客户端

【讨论】:

因此,如果我注入 HttpClient 而不是 IHttpClientFactory(尽管我有相同的 startup.cs 设置),我会失去工厂功能(池等),对吗?我觉得没关系。 一些额外的点作为 HttpClientFactory 内部创建 HttpMessageHandler 对象。因此,每次您在内部创建一个新的 HttpClientFactory 对象时,您都在创建 HttpMessageHandler 对象。并且有一个HttpMessageHandler链。 HttpClientFactory的好处它会重用现有的HttpMessageHandler实例,如果一个可用,如果没有,它会创建一个新的HttpMessageHandler实例

以上是关于依赖注入:HttpClient 还是 HttpClientFactory?的主要内容,如果未能解决你的问题,请参考以下文章

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

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

如何将 RateLimiter 的 HttpClient DelegatingHandler 与依赖注入一起使用?

如何为构造函数包含 HttpClient 和一些字符串的类设置一些 .NET Core 依赖注入?

当我在 HttpInterceptor 类中注入使用 HttpClient 的服务时,Angular 6 进入循环依赖的无限循环

从依赖注入配置进行依赖调用