惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

IT之家
IT之家
A
About on SuperTechFans
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
N
Netflix TechBlog - Medium
Microsoft Security Blog
Microsoft Security Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - 三生石上(FineUI控件)
博客园 - 聂微东
博客园 - Franky
D
Docker
Martin Fowler
Martin Fowler
Engineering at Meta
Engineering at Meta
The Cloudflare Blog
人人都是产品经理
人人都是产品经理
Last Week in AI
Last Week in AI
U
Unit 42
F
Fortinet All Blogs
H
Help Net Security
Blog — PlanetScale
Blog — PlanetScale
Microsoft Azure Blog
Microsoft Azure Blog
罗磊的独立博客
P
Proofpoint News Feed
月光博客
月光博客
G
Google Developers Blog

博客园 - 宁静致远.

Swagger 页面登录验证中间件(Basic认证) Hangfire 的 ASP.NET Core 应用程序始终运行在IIS上 DevExpress 无法打开WinForm设计窗体,报错: 类型 universe 无法解析程序集: System, Version=2.0.0.0 PowerDesigner参数设置 Hangfire 任务调度配置 雪花漂移ID,Yitter.IdGenerator 封装成一个适用于 ASP.NET Core 6.0 的服务组件 解决 Hangfire 中使用HttpClient 任务超时问题 TaskCanceledException: The request was canceled due to the configured HttpClient.Timeout of 100 seconds elapsing. ASP.NET Core API 自定义全局异常 Dapper模糊查询Like 删除重复记录,仅留一条 Task 多线程执行 使用Hangfire+.NET 6实现定时任务管理(推荐) Json 序列化,将对象序列化为Json字符串(此Json序列化,是“不安全的放松JSON转义”,即不会将物特殊符号和中文进行转码) 查询指定数据库中有全部表名,快速定位列名所在表 Sql 查询工具 Sql 数据库表查询 Json 列 显示实体之间的外键关系 调整PowerDesigner各种字体大小 工厂里常说的QC, IQC,IPQC,QA都是干什么的? appsettings.json launchSettings.json 发布 配置
使用 IHttpClientFactory 处理请求和响应
宁静致远. · 2025-02-02 · via 博客园 - 宁静致远.

 HttpClient 类型是在 2012 年发布的 .NET Framework 4.5 中引入的。 换句话说,它已经存在一段时间了。 HttpClient 用于从由 Uri 标识的网络资源发出 HTTP 请求和处理 HTTP 响应。 HTTP 协议占所有 Internet 流量的绝大部分。

根据推动最佳做法的新式应用程序开发原则,IHttpClientFactory 充当工厂抽象,可以使用自定义配置创建 HttpClient 实例。

.NET Core 2.1 中引入了 IHttpClientFactory。 常见的基于 HTTP 的 .NET 工作负载可以轻松利用可复原和瞬态故障处理第三方中间件。

IHttpClientFactory 创建的 HttpClient 实例的生存期管理与手动创建的实例完全不同。 策略是使用由 IHttpClientFactory 创建的短期客户端,或设置了 PooledConnectionLifetime 的长期客户端。

IHttpClientFactory 类型

安装 Microsoft.Extensions.Http NuGet 包

调用任何 AddHttpClient 扩展方法时,将 IHttpClientFactory 和相关服务添加到 IServiceCollection。 IHttpClientFactory 类型具有以下优点:

  • 将 HttpClient 类公开为 DI 就绪类型。
  • 提供一个中心位置,用于命名和配置逻辑 HttpClient 实例。
  • 通过 HttpClient 中的委托处理程序来编码出站中间件的概念。
  • 提供基于 Polly 的中间件的扩展方法,以利用 HttpClient 中的委托处理程序。
  • 管理基础 HttpClientHandler 实例的缓存和生存期。 自动管理可避免手动管理 HttpClient 生存期时出现的常见域名系统 (DNS) 问题。
  • (通过 ILogger)添加可配置的记录体验,以处理工厂创建的客户端发送的所有请求。

使用模式

在应用中可以通过以下多种方式使用 IHttpClientFactory

基本用法

若要注册 IHttpClientFactory,请在 Program.cs 文件中调用 AddHttpClient

builder.Services.AddHttpClient();

使用服务可能需要 IHttpClientFactory 作为带有 DI 的构造函数参数。 以下代码使用 IHttpClientFactory 来创建 HttpClient 实例:  

命名客户端

在以下情况下,命名客户端是一个不错的选择:

  • 应用需要 HttpClient 的许多不同用法。
  • 许多 HttpClient 实例具有不同的配置。

可以在 IServiceCollection 上注册时指定命名 HttpClient 的配置:

string? httpClientName = builder.Configuration["TodoHttpClientName"];
if (string.IsNullOrEmpty(httpClientName))
{
  throw new ArgumentException("HttpClientName cannot be null or empty", nameof(httpClientName));
}
builder.Services.AddHttpClient(httpClientName, client =>
{
  client.BaseAddress = new Uri("https://jsonplaceholder.typicode.com/");
  //client.DefaultRequestHeaders.UserAgent.ParseAdd("dotnet-docs");
});

配置文件 appsettings.json :

{
    "TodoHttpClientName": "JsonPlaceholderApi"
}

创建客户端

每次调用 CreateClient 时:

  • 创建 HttpClient 的新实例。
  • 调用配置操作。

要创建命名客户端,请将其名称传递到 CreateClient 中:

using System.Net.Http;
using System.Text.Json;
using HelperToolProject.Core.ProjectAggregate;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;

namespace HelperToolProject.Web.Api;
[Route("api/[controller]")]
[ApiController]
public class TodoController : ControllerBase
{
  ILogger<TodoController> _logger;
  IConfiguration _configuration;
  IHttpClientFactory _httpClientFactory;
  public TodoController(IHttpClientFactory httpClientFactory, ILogger<TodoController> logger, IConfiguration configuration)
  {
    _logger = logger;
    _configuration = configuration;
    _httpClientFactory = httpClientFactory;
  }

  [HttpGet("UserTodoes")]
  public async Task<ActionResult<IEnumerable<ToDo>?>> GetUserTodoesAsync()
  {//1.基本用法
    string uri = $"https://jsonplaceholder.typicode.com/todos/";
    using HttpClient httpClient = _httpClientFactory.CreateClient();
    try
    {
      var todos = await httpClient.GetFromJsonAsync<IEnumerable<ToDo>>(uri, new JsonSerializerOptions(JsonSerializerDefaults.Web));
      return Ok(todos);
    }
    catch (Exception ex)
    {
      _logger.LogError(ex, "Error getting todos");
      return StatusCode(StatusCodes.Status500InternalServerError, "Error getting todos");
    }
  }

  [HttpGet("{userId:int}")]
  public async Task<ActionResult<IEnumerable<ToDo>?>> GetUserTodoAsync(int userId)
  {//2.指定HttpClient名称用法,场景:请求多个不同的网址,或者请求同一个网址但是需要不同的配置
    string uri = $"todos?userId={userId}";
    string? httpClientName = _configuration["TodoHttpClientName"];
    using HttpClient httpClient = _httpClientFactory.CreateClient(httpClientName ?? "");

    try
    {
      var todo = await httpClient.GetFromJsonAsync<IEnumerable<ToDo>?>(uri, new JsonSerializerOptions(JsonSerializerDefaults.Web));
      return Ok(todo);
    }
    catch (Exception ex)
    {
      _logger.LogError(ex, "Error getting todo");
      return StatusCode(StatusCodes.Status500InternalServerError, "Error getting todo");
    }
  }
}

public class ToDo
{
  public int UserId { get; set; }
  public int Id { get; set; }
  public string Title { get; set; }
  public bool Completed { get; set; }
}

发出 POST、PUT 和 DELETE 请求

using System.Net.Http;
using System.Net.Mime;
using System.Text;
using System.Text.Json;
using HelperToolProject.Core.ProjectAggregate;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;

namespace HelperToolProject.Web.Api;
[Route("api/[controller]")]
[ApiController]
public class TodoController : ControllerBase
{
  ILogger<TodoController> _logger;
  IConfiguration _configuration;
  IHttpClientFactory _httpClientFactory;
  string? httpClientName;
  public TodoController(IHttpClientFactory httpClientFactory, ILogger<TodoController> logger, IConfiguration configuration)
  {
    _logger = logger;
    _configuration = configuration;
    _httpClientFactory = httpClientFactory;
    httpClientName = _configuration["TodoHttpClientName"];

  }

  [HttpGet("UserTodoes")]
  public async Task<ActionResult<IEnumerable<ToDo>?>> GetUserTodoesAsync()
  {//1.基本用法
    string uri = $"https://jsonplaceholder.typicode.com/todos/";
    using HttpClient httpClient = _httpClientFactory.CreateClient();
    try
    {
      var todos = await httpClient.GetFromJsonAsync<IEnumerable<ToDo>>(uri, new JsonSerializerOptions(JsonSerializerDefaults.Web));
      return Ok(todos);
    }
    catch (Exception ex)
    {
      _logger.LogError(ex, "Error getting todos");
      return StatusCode(StatusCodes.Status500InternalServerError, "Error getting todos");
    }
  }

  [HttpGet("{userId:int}")]
  public async Task<ActionResult<IEnumerable<ToDo>?>> GetUserTodoAsync(int userId)
  {//2.指定HttpClient名称用法,场景:请求多个不同的网址,或者请求同一个网址但是需要不同的配置
    string uri = $"todos?userId={userId}";
    using HttpClient httpClient = _httpClientFactory.CreateClient(httpClientName ?? "");
    try
    {
      var todo = await httpClient.GetFromJsonAsync<IEnumerable<ToDo>?>(uri, new JsonSerializerOptions(JsonSerializerDefaults.Web));
      return Ok(todo);
    }
    catch (Exception ex)
    {
      _logger.LogError(ex, "Error getting todo");
      return StatusCode(StatusCodes.Status500InternalServerError, "Error getting todo");
    }
  }
  [HttpPost]
  public async Task CreateItemAsync(ToDo item)
  {
    using HttpClient httpClient = _httpClientFactory.CreateClient(httpClientName ?? "");

    using StringContent json = new(
        JsonSerializer.Serialize(item, new JsonSerializerOptions(JsonSerializerDefaults.Web)),
        Encoding.UTF8,
        MediaTypeNames.Application.Json);

    using HttpResponseMessage httpResponse =
        await httpClient.PostAsync("/api/items", json);

    httpResponse.EnsureSuccessStatusCode();
  }
  [HttpPut]
  public async Task UpdateItemAsync(ToDo item)
  {
    using HttpClient httpClient = _httpClientFactory.CreateClient(httpClientName ?? "");

    using StringContent json = new(
        JsonSerializer.Serialize(item, new JsonSerializerOptions(JsonSerializerDefaults.Web)),
        Encoding.UTF8,
        MediaTypeNames.Application.Json);

    using HttpResponseMessage httpResponse =
        await httpClient.PutAsync($"/api/items/{item.Id}", json);

    httpResponse.EnsureSuccessStatusCode();
  }
  [HttpDelete("id:int")]
  public async Task DeleteItemAsync(int id)
  {
    using HttpClient httpClient = _httpClientFactory.CreateClient(httpClientName ?? "");

    using HttpResponseMessage httpResponse =
        await httpClient.DeleteAsync($"/api/items/{id}");

    httpResponse.EnsureSuccessStatusCode();
  }

}

public class ToDo
{
  public int UserId { get; set; }
  public int Id { get; set; }
  public string Title { get; set; }
  public bool Completed { get; set; }
}

参考网址:https://learn.microsoft.com/zh-cn/dotnet/core/extensions/httpclient-factory