在 ASP.NET Core 的外部库中使用 HttpClient
Using HttpClient in external library for ASP.NET Core
简介
我正在开发 SDK(这只是 REST API 的包装器)。此 SDK 在内部使用 HttpClient 为 API 发出请求。 SDK 以 .NET Standard 2.1 为目标。这是简化的代码。
public class SomeSdk
{
private readonly HttpClient _httpClient;
public SomeSdk(<some-settings>)
{
_httpClient = new HttpClient(<some-settings>);
}
public async Task<string> GetSomethingFromApiAsync()
{
return await _httpClient.GetStringAsync(...);
}
}
问题
其他开发人员正在 ASP.NET 核心项目中使用该 SDK。我知道 HttpClient 的问题,我知道 MS DOCS 建议注入 HttpClientFactory 以避免 SocketException 并反映 DNS 更改。
第一个想到的解决方案是让用户在SDK构造函数或其他方法中传递HttpClient(即来自HttpClientFactory)。像这样。
public async Task<string> GetSomethingFromApiAsync(HttpClient clientFromFactory)
{
return await clientFromFactory.GetStringAsync(...);
}
然而,SDK 在使用 HttpClient 之前会对其进行配置(代理、超时等),因此存在问题,因此应将其初始化保留在 SDK 构造函数中。
问题
我目前的解决方案是在 ASP.NET 核心项目中将 SDK 作为单例注入并接受 DNS 反射问题。我还是想问问有没有人会推荐我一个更好的方法来解决这个问题。
非常感谢,亚当。
实例化 HttpClient 的更好方法是使用 DI。
因此,假设您的 SDK 项目中有一些 class 这样的
public interface ISomeSdk
{
Task<string> GetSomethingFromApiAsync();
}
public class SomeSdk: ISomeSdk
{
private readonly HttpClient _httpClient;
public SomeSdk(HttpClient httpClient)
{
_httpClient = httpClient;
}
public async Task<string> GetSomethingFromApiAsync()
{
return await _httpClient.GetStringAsync("");
}
}
你可以很方便地添加一个扩展方法来通过DI注册它(这里是在SDK项目中)
public static class HttpClientExtensions
{
public static void RegisterSdk(this IServiceCollection services)
{
services.AddHttpClient<ISomeSdk, SomeSdk>(client =>
{
client.Timeout = TimeSpan.FromSeconds(60);
client.BaseAddress = new Uri("https://google.com");
});
}
}
之后在启动项目中这个class可以添加到DI注册中
public void ConfigureServices(IServiceCollection services)
{
services.RegisterSdk();
//...
什么时候需要它就可以使用它
public class SomeController : ControllerBase
{
private readonly ISomeSdk _someSdk;
public SomeController(ISomeSdk someSdk)
{
_someSdk = someSdk;
}
更好的方法是使用 HttpClientFactory 创建 HttpClient 实例。
HttpClientFactory 可以创建和管理新的 HttpClient 实例,但在创建新的 HttpClient 实例时,它不会重新创建新的消息处理程序,而是从池中获取一个。然后,它使用该消息处理程序将请求发送到 API。处理程序的默认生命周期设置为两分钟,在此期间,对新 HttpClient 的任何请求都可以重用现有的消息处理程序和连接。这意味着我们不必为每个请求创建一个新的消息处理程序,也不必打开一个新连接,从而防止套接字耗尽问题。
有了 HttpClientHandler,我们可以集中我们的 HttpClient 配置。如果您使用 HttpClientHandler 在每个服务 class 中重复相同的配置,则可以防止这种情况发生。
您可以在此处找到如何使用它的示例 https://docs.microsoft.com/en-us/aspnet/core/fundamentals/http-requests?view=aspnetcore-5.0