.NET Core中泛型类依赖注入的优化实现方案咨询
优化方案说明
首先需要修正原APIClient的一个关键问题:每次创建HttpClient和HttpClientHandler会导致TCP端口耗尽,违反ASP.NET Core的HttpClient最佳实践。正确的做法是注入HttpClient(由DI容器管理生命周期)或使用IHttpClientFactory。
修正后的基础泛型客户端实现
public class APIClient<T1, T2> : IApiClient<T1, T2> where T1 : class where T2 : class { private readonly HttpClient _httpClient; public APIClient(HttpClient httpClient) { _httpClient = httpClient; } public async Task<T2> PostToEndPoint(string url, T1 input) { // 注意:方法名是PostToEndPoint,内部应使用PostAsJsonAsync而非PutAsJsonAsync var response = await _httpClient.PostAsJsonAsync(url, input); response.EnsureSuccessStatusCode(); // 建议添加,确保请求成功 var content = await response.Content.ReadAsStringAsync(); return JsonConvert.DeserializeObject<T2>(content); } } public interface IApiClient<T1, T2> where T1 : class where T2 : class { Task<T2> PostToEndPoint(string url,T1 input); }
注册时改用AddHttpClient管理:
// 基础注册 builder.Services.AddHttpClient(typeof(IApiClient<,>), typeof(APIClient<,>)); // 如需统一配置BaseAddress等参数 builder.Services.AddHttpClient<IApiClient<,>, APIClient<,>>() .ConfigureHttpClient(client => { client.BaseAddress = new Uri("https://your-api-base-url.com/"); });
方案一:工厂模式减少注入实例数量
通过工厂类统一管理不同泛型参数的IApiClient实例获取,控制器仅需注入工厂。
工厂接口与实现
public interface IApiClientFactory { IApiClient<TInput, TOutput> CreateClient<TInput, TOutput>() where TInput : class where TOutput : class; } public class ApiClientFactory : IApiClientFactory { private readonly IServiceProvider _serviceProvider; public ApiClientFactory(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; } public IApiClient<TInput, TOutput> CreateClient<TInput, TOutput>() where TInput : class where TOutput : class { return _serviceProvider.GetRequiredService<IApiClient<TInput, TOutput>>(); } }
注册工厂
builder.Services.AddScoped<IApiClientFactory, ApiClientFactory>();
控制器使用示例
public class ProjectController : ControllerBase { private readonly IApiClientFactory _apiClientFactory; public ProjectController(IApiClientFactory apiClientFactory) { _apiClientFactory = apiClientFactory; } public async Task<IActionResult> ProcessData() { var client1 = _apiClientFactory.CreateClient<ClassA, ClassB>(); var result1 = await client1.PostToEndPoint("/api/endpoint1", new ClassA()); var client2 = _apiClientFactory.CreateClient<ClassC, ClassD>(); var result2 = await client2.PostToEndPoint("/api/endpoint2", new ClassC()); // ...业务逻辑处理 return Ok(); } }
方案二:重构为非泛型客户端+泛型方法
如果所有API调用逻辑一致,可将泛型从类级别移至方法级别,仅需注入单个客户端实例。
非泛型接口与实现
public interface IApiClient { Task<TOutput> PostToEndPoint<TInput, TOutput>(string url, TInput input) where TInput : class where TOutput : class; } public class ApiClient : IApiClient { private readonly HttpClient _httpClient; public ApiClient(HttpClient httpClient) { _httpClient = httpClient; } public async Task<TOutput> PostToEndPoint<TInput, TOutput>(string url, TInput input) where TInput : class where TOutput : class { var response = await _httpClient.PostAsJsonAsync(url, input); response.EnsureSuccessStatusCode(); var content = await response.Content.ReadAsStringAsync(); return JsonConvert.DeserializeObject<TOutput>(content); } }
注册客户端
builder.Services.AddHttpClient<IApiClient, ApiClient>() .ConfigureHttpClient(client => { client.BaseAddress = new Uri("https://your-api-base-url.com/"); });
控制器使用示例
public class ProjectController : ControllerBase { private readonly IApiClient _apiClient; public ProjectController(IApiClient apiClient) { _apiClient = apiClient; } public async Task<IActionResult> ProcessData() { var result1 = await _apiClient.PostToEndPoint<ClassA, ClassB>("/api/endpoint1", new ClassA()); var result2 = await _apiClient.PostToEndPoint<ClassC, ClassD>("/api/endpoint2", new ClassC()); var result3 = await _apiClient.PostToEndPoint<ClassE, ClassF>("/api/endpoint3", new ClassE()); // ...业务逻辑处理 return Ok(); } }
方案对比
- 方案一:保留原有泛型类结构,适合不同泛型参数的客户端需要独立配置(如不同BaseAddress、超时时间)的场景,通过工厂统一管理实例获取。
- 方案二:代码更精简,减少DI容器中的实例数量,适合所有API调用逻辑完全一致的场景。
内容的提问来源于stack exchange,提问作者Sumit
相关产品推荐
相关产品推荐

