如何将一个HttpClient注入到多个服务中

Lor*_*eno 8 .net c# dependency-injection .net-core

我正在构建一个 API 客户端。我的 API 相当大,所以我决定将其分成大约 5 个(私有)子客户端,每个子客户端涵盖 API 的不同部分。5 个客户端使用起来不太舒服,所以我希望将它们置于 1 (public) 之下ApiClient,这将充当这 5 个客户端之上的一种外观。问题是我可能应该HttpClient在所有这些子客户端之间共享一个。据我所知,我可以做这样的事情:

services.AddHttpClient<SubClient1>(c => c.BaseAddress = new System.Uri("https://myapi.com"));
Run Code Online (Sandbox Code Playgroud)

通过上面的行,我的SubClient1将被注入到我的公共中ApiClient,并且HttpClient已经使用BaseAddress. 现在,我如何注册所有 5 个子客户端(SubClient1SubClient2SubClient3、 ...)以便他们每个人都收到相同的信息HttpClient?我认为下面的代码将创建 5 个HttpClient实例:

services.AddHttpClient<SubClient1>(c => c.BaseAddress = new System.Uri("https://myapi.com"));
services.AddHttpClient<SubClient2>(c => c.BaseAddress = new System.Uri("https://myapi.com"));
services.AddHttpClient<SubClient3>(c => c.BaseAddress = new System.Uri("https://myapi.com"));
services.AddHttpClient<SubClient4>(c => c.BaseAddress = new System.Uri("https://myapi.com"));
services.AddHttpClient<SubClient5>(c => c.BaseAddress = new System.Uri("https://myapi.com"));
Run Code Online (Sandbox Code Playgroud)

我该如何解决这个问题?

Ken*_*lac 7

我不同意@Athanasios Kataras 的回答。但我不明白为什么你需要将其变成单例。

基本上有 3 种方法可以将 http 客户端依赖注入到服务中;直接、键入和命名。@Athanasios 所做的是直接的。但在这种情况下,我相信命名的 HttpClient 是正确的选择。但是您也可以只使用注入到子客户端中的类型,假设客户端的行为在所有子客户端中都是相同的。

在startup.cs或program.cs中(取决于.net 5.0或.net 6.0)

public class Startup
{
    private IConfiguration Configuration { get; }
    private IHostEnvironment HostEnvironment { get; set; }

    public Startup(IConfiguration configuration, IHostEnvironment env)
    {
        Configuration = configuration;
        HostEnvironment = env;
    }

    public void ConfigureServices(IServiceCollection services)
    {
        //Named client
        services.AddHttpClient("myapi", c =>
        {
            c.BaseAddress = new System.Uri("https://myapi.com");
        });

        //Typed client
        services.AddHttpClient<iMyApi, MyApi>(c => 
            c.BaseAddress = new System.Uri("https://myapi.com");
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

这会将 HttpClient 添加到 HttpClientFactory,您现在可以在任何项目中使用它。

子客户端.cs

public class SubClient
{
    private readonly IHttpClientFactory httpFactory;
    private readonly HttpClient namedClient;
    private readonly iMyApi typedClient;
    private readonly static string clientName = "myapi";

    public SubClient(IHttpClientFactory httpClientFactory, iMyApi myApiClient)
    {
        this.namedClient = httpClientFactory.Create(clientName);
        this.typedClient = myApiClient;
    }
}
Run Code Online (Sandbox Code Playgroud)

对于类型化客户端,它取决于您创建一个实现 api 端点的实现。这样做的优点是您拥有一个可在任何服务中使用的临时客户端。并且您可以将自己从我怀疑的大量重复代码中解放出来。


Ath*_*ras 4

您正在使用HttpClientFactory,因此将 的构建委托HttpClient给工厂。

基于文档:https://learn.microsoft.com/en-us/dotnet/architecture/microservices/implement-resilient-applications/use-httpclientfactory-to-implement-resilient-http-requests

如前面的代码所示注册客户端服务,使 DefaultClientFactory 为每个服务创建一个标准 HttpClient。

它是有意这样做的,以便您可以根据服务配置客户端。

就资源而言,你被转换了。这就是客户工厂的最初目的:

每次从 IHttpClientFactory 获取 HttpClient 对象时,都会返回一个新实例。但每个 HttpClient 都使用由 IHttpClientFactory 池化和重用的 HttpMessageHandler,以减少资源消耗,只要 HttpMessageHandler 的生命周期尚未过期。

处理程序池是可取的,因为每个处理程序通常管理其自己的底层 HTTP 连接;创建过多的处理程序可能会导致连接延迟。某些处理程序还无限期地保持连接打开,这可能会阻止处理程序对 DNS 更改做出反应。

如果您不想使用推荐的工厂方式,您可以执行以下操作:https: //nodogmablog.bryanhogan.net/2017/10/reusing-httpclient-with-dependency-injection/

public void ConfigureServices(IServiceCollection services)
{
    Uri endPointA = new Uri("http://localhost:58919/"); // this is the endpoint HttpClient will hit
    HttpClient httpClient = new HttpClient()
    {
        BaseAddress = endPointA,
    };

    ServicePointManager.FindServicePoint(endPointA).ConnectionLeaseTimeout = 60000; // sixty seconds

    services.AddSingleton<HttpClient>(httpClient); // note the singleton
    services.AddMvc();
}
Run Code Online (Sandbox Code Playgroud)