C# IHttpClientFactory
1124 字
6 分钟
C# IHttpClientFactory
C# 中 IHttpClientFactory 的介绍和最佳实践
在 .NET 应用程序中进行 HTTP 请求时,HttpClient 是最常用的类。然而,直接使用 HttpClient 可能会导致一些问题,如端口耗尽和 DNS 更新问题。IHttpClientFactory 是 .NET Core 2.1 引入的一个接口,旨在解决这些问题并提供更好的 HTTP 客户端管理。
1. 为什么需要 IHttpClientFactory?
1.1 直接使用 HttpClient 的问题
- 端口耗尽:每次创建新的
HttpClient实例都会创建新的套接字连接,可能导致端口耗尽。 - DNS 更新问题:
HttpClient默认会缓存 DNS 记录,即使 DNS 记录发生变化,也不会立即更新。 - 资源管理:需要手动管理
HttpClient的生命周期,容易导致资源泄漏。
1.2 IHttpClientFactory 的优势
- 集中管理:通过工厂模式集中管理
HttpClient实例的创建和配置。 - 生命周期管理:自动管理底层
HttpMessageHandler的生命周期,避免端口耗尽问题。 - 可配置性:支持命名客户端和类型化客户端,便于配置不同的 HTTP 客户端。
- 依赖注入友好:与 ASP.NET Core 的依赖注入系统无缝集成。
- 中间件支持:可以轻松添加日志、重试、熔断等中间件。
2. 配置 IHttpClientFactory
2.1 在 ASP.NET Core 中配置
在 Program.cs 或 Startup.cs 中添加服务:
// Program.cs (.NET 6+)var builder = WebApplication.CreateBuilder(args);
// 添加 HttpClient 工厂服务builder.Services.AddHttpClient();
var app = builder.Build();2.2 在控制台应用中配置
using Microsoft.Extensions.DependencyInjection;using Microsoft.Extensions.Hosting;
var host = Host.CreateDefaultBuilder(args) .ConfigureServices((context, services) => { services.AddHttpClient(); }) .Build();3. 使用 IHttpClientFactory
3.1 基本用法
通过依赖注入 IHttpClientFactory 并创建客户端:
public class MyService{ private readonly IHttpClientFactory _httpClientFactory;
public MyService(IHttpClientFactory httpClientFactory) { _httpClientFactory = httpClientFactory; }
public async Task<string> GetDataAsync() { var client = _httpClientFactory.CreateClient(); var response = await client.GetAsync("https://api.example.com/data"); response.EnsureSuccessStatusCode(); return await response.Content.ReadAsStringAsync(); }}3.2 命名客户端
为不同的服务配置不同的客户端:
// 配置服务builder.Services.AddHttpClient("GitHub", client =>{ client.BaseAddress = new Uri("https://api.github.com/"); client.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json"); client.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactory-Sample");});
// 使用命名客户端public class GitHubService{ private readonly IHttpClientFactory _httpClientFactory;
public GitHubService(IHttpClientFactory httpClientFactory) { _httpClientFactory = httpClientFactory; }
public async Task<string> GetRepositoriesAsync() { var client = _httpClientFactory.CreateClient("GitHub"); var response = await client.GetAsync("repositories"); response.EnsureSuccessStatusCode(); return await response.Content.ReadAsStringAsync(); }}3.3 类型化客户端
创建强类型的客户端类,这是推荐的方式:
// 定义类型化客户端public class GitHubClient{ private readonly HttpClient _httpClient;
public GitHubClient(HttpClient httpClient) { _httpClient = httpClient; }
public async Task<List<Repository>> GetRepositoriesAsync() { var response = await _httpClient.GetAsync("repositories"); response.EnsureSuccessStatusCode(); var content = await response.Content.ReadAsStringAsync(); return JsonSerializer.Deserialize<List<Repository>>(content); }}
// 配置类型化客户端builder.Services.AddHttpClient<GitHubClient>(client =>{ client.BaseAddress = new Uri("https://api.github.com/"); client.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json"); client.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactory-Sample");});
// 使用类型化客户端public class MyController : ControllerBase{ private readonly GitHubClient _gitHubClient;
public MyController(GitHubClient gitHubClient) { _gitHubClient = gitHubClient; }
public async Task<IActionResult> GetRepositories() { var repositories = await _gitHubClient.GetRepositoriesAsync(); return Ok(repositories); }}4. 最佳实践
4.1 优先使用类型化客户端
类型化客户端提供了以下优势:
- 强类型支持,编译时检查
- 代码更清晰,易于维护
- 可以封装业务逻辑
4.2 正确配置 HttpClient
builder.Services.AddHttpClient<GitHubClient>(client =>{ // 设置合理的超时时间 client.Timeout = TimeSpan.FromSeconds(30);
// 设置基础地址 client.BaseAddress = new Uri("https://api.github.com/");
// 设置默认请求头 client.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json"); client.DefaultRequestHeaders.Add("User-Agent", "YourApp-Name");});4.2 避免反模式
- 不要在每次请求时创建新的
HttpClient实例 - 不要在
using块中使用HttpClient(除非使用IHttpClientFactory) - 不要手动管理
HttpClient的生命周期
5. 高级配置
5.1 自定义消息处理程序
创建自定义的 DelegatingHandler:
public class LoggingHandler : DelegatingHandler{ private readonly ILogger<LoggingHandler> _logger;
public LoggingHandler(ILogger<LoggingHandler> logger) { _logger = logger; }
protected override async Task<HttpResponseMessage> SendAsync( HttpRequestMessage request, CancellationToken cancellationToken) { _logger.LogInformation($"Sending request to {request.RequestUri}");
var response = await base.SendAsync(request, cancellationToken);
_logger.LogInformation($"Response status: {response.StatusCode}");
return response; }}
// 注册处理程序builder.Services.AddTransient<LoggingHandler>();
builder.Services.AddHttpClient<GitHubClient>(client =>{ client.BaseAddress = new Uri("https://api.github.com/");}).AddHttpMessageHandler<LoggingHandler>();5.2 多个客户端配置
为不同的服务配置不同的客户端:
// GitHub 客户端builder.Services.AddHttpClient<GitHubClient>(client =>{ client.BaseAddress = new Uri("https://api.github.com/"); client.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json");});
// 其他 API 客户端builder.Services.AddHttpClient<PaymentService>(client =>{ client.BaseAddress = new Uri("https://api.payment.com/"); client.Timeout = TimeSpan.FromSeconds(60);});6. 总结
IHttpClientFactory 是 .NET 中管理 HttpClient 的最佳方式,它解决了直接使用 HttpClient 的各种问题,并提供了以下优势:
- 资源管理:自动管理
HttpMessageHandler的生命周期,避免端口耗尽 - 配置灵活性:支持命名客户端和类型化客户端
- 依赖注入集成:与 ASP.NET Core 的 DI 系统无缝集成
- 中间件支持:可以轻松添加日志、重试、熔断等中间件
- 最佳实践:遵循 Microsoft 推荐的 HTTP 客户端使用模式
在开发新的 .NET 应用程序时,强烈建议使用 IHttpClientFactory 而不是直接创建 HttpClient 实例。这不仅提高了应用程序的可靠性,还使代码更易于维护和测试。
参考资料
支持与分享
如果这篇文章对你有帮助,欢迎分享给更多人或赞助支持!
C# IHttpClientFactory
https://firefly.cuteleaf.cn/posts/csharp-ihttpclientfactory/ 相关文章 智能推荐
1
POCO(Plain Old CLR Object)简介
C# 介绍 POCO(Plain Old CLR Object)的概念、特征以及在现代 C# 开发中的应用,特别是在领域驱动设计(DDD)和 ORM(如 Entity Framework Core)中的重要性。
2
Avalonia 动态加载图片/动态修改背景图
C# 介绍在 Avalonia 框架中动态加载图片的几种常用方法,包括从本地资源、Web URL 和字节数组加载图片的实现步骤。
3
StarRailAssistant - 崩铁自动化助手
SRA StarRailAssistant(SRA)是一个基于图像识别的崩铁自动化程序,帮您完成从启动到退出的崩铁日常。支持多账号切换、自动剧情、差分宇宙刷等级、货币战争等功能。
4
Python cmd2:构建强大的命令行解释器
Python 介绍 Python cmd2 包的使用方法,用于构建强大的命令行解释器(CLI)程序,扩展 Python 标准库的 cmd 模块。
5
Python cmd2:应用初始化、多行命令与启动命令
Python 介绍 cmd2 应用的初始化配置、类变量与实例属性、多行命令的使用,以及启动时执行命令的多种方式。
随机文章 随机推荐