Net Core HttpClient-类型客户端生存期



我正试图在我的服务中注入IHttpClientFactory,用于外部api调用并与DI Container一起使用。因为为每个请求创建一个新的CCD_;Typed Client";,我需要在startup.cs 中注册这样的服务

services.AddHttpClient<IMyService, MyService>(options => 
{
options.BaseUrl = new Uri("https://myApi.com");
// you can also give default request headers here.
// And you can use polly for resillience of your services.
});

我的服务

public class MyService : IMyService
{
private HttpClient _client;
private ILogger<MyService> _logger;
private IAnotherSingletonService _anotherSingletonService;

public MyService(
HttpClient client,
ILogger<MyService> logger,
IAnotherSingletonService anotherSingletonService)
{
_client = client;
_logger = logger;
_anotherSingletonService = anotherSingletonService;
}
public async Task MyMethod()
{
var URL = "/api/products"; //base url is in startup.cs already
var response = await _client.GetAsync(URL);
//use other registered services...
}
}

所以,我的问题是AddHttpClient添加了我的瞬态寿命服务。这被称为";Typed Client";。但是我想使MyService成为单例。我想知道如何使用Typed客户端来实现这一点。


编辑-第二种方式:

在这里,我尝试了IHttpClientFactory的基本用法

Startup.cs

services.AddHttpClient();
services.AddSingleton<IMyService, MyService>();

MyService

public class MyService : IMyService
{
private IHttpClientFactory _httpClientFactory;
private ILogger<MyService> _logger;
private IAnotherSingletonService _anotherSingletonService;

public MyService(
IHttpClientFactory httpClientFactory,
ILogger<MyService> logger,
IAnotherSingletonService anotherSingletonService)
{
_httpClientFactory= httpClientFactory;
_logger = logger;
_anotherSingletonService = anotherSingletonService;
}
public async Task MyMethod()
{
using(var httpClient = _httpClientFactory.CreateClient())
{
var URL = "/api/products"; //base url is in startup.cs already
var response = await httpClient.GetAsync(URL);
}

//use other registered services...
}
}

原始HttpClient有两个问题:

  • 使用using (new HttpClient())可能会导致端口耗尽,因为它为每个HttpClient实例使用单独的连接
  • 使用static HttpClient可能会错过DNS更新,因为它无限期地使用单个连接

TL;DR:从那以后。NET核心2.1,您可以使用static HttpClient。您仍然不应该使用using (new HttpClient())

更长的答案:

问题实际上与HttpClient实例无关;这是关于套接字生存期的问题,它由内部HttpMessageHandler(如果您有委派处理程序,则是最后一个HttpMessageHandler)控制。

在。NET Core 2.0及更早版本,默认情况下为HttpClientHandlerHttpClientHandler为每个实例建立一个套接字连接。因此,为了解决这个问题,ASP。NET团队创建了IHttpClientFactory,它汇集了HttpClientHandler(而不是根据需要创建和销毁的HttpClient0包装器)。

在。NET Core 2.1及更新版本,默认的内部处理程序是SocketsHttpHandler,它有自己的连接池。因此,在这些平台上,单个static HttpClient实例是可以的。如果您希望主动检测DNS更改,则可能希望设置PooledConnectionLifetime属性。

有些人仍然喜欢IHttpClientFactory,因为它有流畅的DI语法,但它不再是所必需的

在您的情况下,由于您的服务是单例的,因此不能使用类型化客户端(这是最好的DI语法IMO)。所以你有两个选择:

  1. 根据需要使用IHttpClientFactory并获得HttpClient(如编辑中所示)。在这种情况下,工厂将为HttpClient实例池HttpClientHandlers(并且每个HttpClientHandler都是一个连接)
  2. 使用static HttpClient。在这种情况下,由HttpClient创建的SocketsHttpHandler将汇集其自己的连接

IHttpClientFactory有一些优点(例如,您可以使用命名客户端,但仍然可以获得良好的DI语法);并且SocketsHttpHandler具有一些优点(例如性能和跨平台一致性)。最终,决定权在你;没有一个明确的赢家。