我正试图在我的服务中注入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及更早版本,默认情况下为HttpClientHandler
。HttpClientHandler
为每个实例建立一个套接字连接。因此,为了解决这个问题,ASP。NET团队创建了IHttpClientFactory
,它汇集了HttpClientHandler
(而不是根据需要创建和销毁的HttpClient
0包装器)。
在。NET Core 2.1及更新版本,默认的内部处理程序是SocketsHttpHandler
,它有自己的连接池。因此,在这些平台上,单个static HttpClient
实例是可以的。如果您希望主动检测DNS更改,则可能希望设置PooledConnectionLifetime
属性。
有些人仍然喜欢IHttpClientFactory
,因为它有流畅的DI语法,但它不再是所必需的。
在您的情况下,由于您的服务是单例的,因此不能使用类型化客户端(这是最好的DI语法IMO)。所以你有两个选择:
- 根据需要使用
IHttpClientFactory
并获得HttpClient
(如编辑中所示)。在这种情况下,工厂将为HttpClient
实例池HttpClientHandler
s(并且每个HttpClientHandler
都是一个连接) - 使用
static HttpClient
。在这种情况下,由HttpClient
创建的SocketsHttpHandler
将汇集其自己的连接
IHttpClientFactory
有一些优点(例如,您可以使用命名客户端,但仍然可以获得良好的DI语法);并且SocketsHttpHandler
具有一些优点(例如性能和跨平台一致性)。最终,决定权在你;没有一个明确的赢家。