面向ASP.NET Core的SDK中HttpClient最优使用方案咨询
最优解决方案
方案1:适配ASP.NET Core DI场景(推荐)
核心思路是封装ASP.NET Core依赖注入扩展方法,将HttpClient的代理、超时、请求头等自定义配置逻辑完全收敛在SDK内部,同时复用官方HttpClientFactory的能力,既不需要使用者手动传入HttpClient,也完美规避Socket耗尽、DNS更新不及时的问题。
- 首先在SDK项目中引入
Microsoft.Extensions.HttpNuGet包,编写DI扩展方法:
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using System.Net; public class SomeSdkSettings { public string ApiBaseUrl { get; set; } public int Timeout { get; set; } = 30; public string ProxyAddress { get; set; } public bool UseProxy { get; set; } } public static class SomeSdkServiceCollectionExtensions { public static IServiceCollection AddSomeSdk(this IServiceCollection services, Action<SomeSdkSettings> configure) { // 注册用户传入的SDK配置 services.Configure(configure); // 为SDK配置专属HttpClient,所有自定义逻辑全部在SDK内部完成 services.AddHttpClient<ISomeSdk, SomeSdk>((sp, client) => { var settings = sp.GetRequiredService<IOptions<SomeSdkSettings>>().Value; client.BaseAddress = new Uri(settings.ApiBaseUrl); client.Timeout = TimeSpan.FromSeconds(settings.Timeout); client.DefaultRequestHeaders.Add("X-Sdk-Version", "1.0.0"); // 其他请求头、默认配置等 }) .ConfigurePrimaryHttpMessageHandler(sp => { var settings = sp.GetRequiredService<IOptions<SomeSdkSettings>>().Value; return new HttpClientHandler { Proxy = settings.UseProxy ? new WebProxy(settings.ProxyAddress) : null, UseProxy = settings.UseProxy }; }); return services; } }
- 调整SDK实现,提供DI专用构造函数:
public interface ISomeSdk { Task<string> GetSomethingFromApiAsync(); } public class SomeSdk : ISomeSdk { private readonly HttpClient _httpClient; // DI场景专用构造函数,注入的HttpClient已经由Factory完成所有自定义配置 public SomeSdk(HttpClient httpClient) { _httpClient = httpClient; } public async Task<string> GetSomethingFromApiAsync() { return await _httpClient.GetStringAsync("target/endpoint"); } }
- 使用者仅需在ASP.NET Core项目的启动代码中一行注册即可,无需关心HttpClient的配置逻辑:
// Program.cs中注册 builder.Services.AddSomeSdk(options => { options.ApiBaseUrl = "https://your-api-domain.com"; options.Timeout = 15; // 其他SDK配置项 }); // 业务代码中直接注入使用 public class SomeController : ControllerBase { private readonly ISomeSdk _someSdk; public SomeController(ISomeSdk someSdk) { _someSdk = someSdk; } }
方案2:兼容非DI/非ASP.NET Core场景
如果你的SDK需要支持控制台、桌面应用等没有内置HttpClientFactory的场景,可以通过显式配置SocketsHttpHandler的PooledConnectionLifetime参数,解决单例SDK下的DNS更新不及时问题,不需要使用者做额外配置:
public class SomeSdk : ISomeSdk { private readonly HttpClient _httpClient; // 非DI场景专用构造函数,内部自行完成所有HttpClient配置 public SomeSdk(SomeSdkSettings settings) { var handler = new SocketsHttpHandler { // 设置连接池生命周期,到期自动回收旧连接,适配DNS变更 PooledConnectionLifetime = TimeSpan.FromMinutes(2), Proxy = settings.UseProxy ? new WebProxy(settings.ProxyAddress) : null, UseProxy = settings.UseProxy }; _httpClient = new HttpClient(handler, disposeHandler: true) { BaseAddress = new Uri(settings.ApiBaseUrl), Timeout = TimeSpan.FromSeconds(settings.Timeout) }; } // DI场景构造函数 public SomeSdk(HttpClient httpClient) { _httpClient = httpClient; } public async Task<string> GetSomethingFromApiAsync() { return await _httpClient.GetStringAsync("target/endpoint"); } }
以上两种方案都可以完全保留SDK内部对HttpClient的配置控制权,同时规避Socket耗尽和DNS更新不及时的问题,无需使用者额外处理HttpClient相关逻辑。
内容的提问来源于stack exchange,提问作者Adam Hrouda
相关产品推荐
相关产品推荐

