IHttpClientFactory

利用IHttpClientFactory可以无缝创建HttpClient实例,避免手动管理它们的生命周期。

当使用ASP.Net Core开发应用程序时,可能经常需要通过HttpClient调用WebAPI的方法以检查终结点是否正常工作。要实现这一点,通常需要实例化HttpClient并使用该实例来调用你的方法。但是直接使用HttpClient也有一些缺点,主要与手动管理实例的生命周期有关。

你可以使用IHttpClientFactory创建HttpClient来避免这些问题。IHttpClientFactory是在.Net Core 2.1引入的,它提供了一个命名,配置和创建HttpClient实例的核心功能,并能自动管理实例的池化和生命周期。

为什么使用IHttpClientFactory?

尽管HttpClient没有直接实现IDisposable接口,但它扩展了System.Net.Http。HttpMessageInvoker,这个类实现了IDisposable。然而,当使用HttpClient实例时,你不应该手动操作释放它们。尽管可以在HttpClient实例上调用Dispose方法,但不推荐这样做。
应该怎么做呢?一种选择是使HttpClient静态化,或者将HttpClient的非静态实例包装在自定义类中,并使其成为单例类。但是更好的替代方法是使用IHttpClientFactory来生成HttpClient的实例,然后使用该实例来调用操作方法。

当你释放HttpClient实例时,连接将保持打开状态长达4分钟。此外,可以在任何时间点打开socket的数量是有限制的——不能同时打开太多socket。因此,当使用太多HttpClient实例时,可能会耗尽socket。
这就是IHttpClientFactory的意义所在。你可以通过利用IHttpClientFactory来创建用于调用HTTP API方法的HttpClient实例,以避免HttpClient所面临的问题。在ASP.NET Core中实现IHttpClientFactory的主要目标是为了确保使用工厂模式创建HttpClient实例的同时避免socket耗尽。

IHttpClientFactory 和HttpClientFactory

IHttpClientFactory是一个由DefaultHttpClientFactory类实现的接口,这是一个工厂模式。DefaultHttpClientFactory实现了IHttpClientFactory和IHttpMessageHandlerFactory接口。IHttpClientFactory提供了ASP.NET Core对创建、缓存和处理HttpClient实例提供了出色的内置支持。
请注意,HttpClientFactory只是一个帮助类,用于创建使用提供的处理程序配置的HttpClient实例。这个类有以下方法:?

1
2
3
Create(DelegatingHandler[])
Create(HttpMessageHandler,DelegatingHandler[])
CreatePipeline(HttpMessageHandler,IEnumerable<DelegatingHandler>)

重载的HttpClientFactory类的Create方法看起来像这样:?

1
2
3
4
5
6
7
8
9
public static HttpClient Create(params DelegatingHandler[] handlers)
{
 return Create(new HttpClientHandler(), handlers);
}
public static HttpClient Create(HttpMessageHandler innerHandler, params DelegatingHandler[] handlers)
{
 HttpMessageHandler pipeline = CreatePipeline(innerHandler, handlers);
 return new HttpClient(pipeline);
}

引入HttpClientFactory和IHttpClientFactory是为了更好地管理HttpMessageHandler实例的生命周期。

在ASP.NET Core中注册IHttpClientFactory实例

你可以在Startup类的ConfigureServices方法中,通过调用IServiceCollection实例上的AddHttpClient扩展方法注册一个IHttpClientFactory类型的实例,如下:?

1
2
3
4
5
public void ConfigureServices(IServiceCollection services)
{
  services.AddControllersWithViews();
  services.AddHttpClient();
}

 

将IHttpClientFactory实例注入到控制器

可以通过如下代码将将IHttpClientFactory实例注入到控制器:?

1
2
3
4
5
6
7
8
9
10
11
public class HomeController : Controller
{
   private IHttpClientFactory _httpClientFactory;
   private readonly ILogger<HomeController> _logger;
   public HomeController(ILogger<HomeController> logger,
   IHttpClientFactory httpClientFactory)
   {
      _logger = logger;
      _httpClientFactory = httpClientFactory;
   }
}

 

 

 

在Action中调用HttpClient

要通过使用IHttpClientFactory创建HttpClient,应该调用CreateClient方法。一旦HttpClient实例可用,就可以在HomeController类的index方法中使用以下代码来调用ValuesController类的Get方法。

1
2
3
4
5
6
7
8
9
public async Task<IActionResult> Index()
{
  HttpClient httpClient = _httpClientFactory.CreateClient();
  httpClient.BaseAddress = new Uri("http://localhost:5000/");
  var response = await httpClient.GetAsync("/api/values");
  string str = await response.Content.ReadAsStringAsync();
  List<string> data = JsonSerializer.Deserialize<List<string>>(str);
  return View(data);
}

 

 

 

使用IHttpClientFactory在ASP.NET Core中创建和管理HttpClient实例

有几种方法可以在应用程序中使用IHttpClientFactory。这包括直接使用IHttpClientFactory、使用命名client和类型client。
基本的或一般的使用模式,即直接使用IHttpClientFactory。请参考“注册一个IHttpClientFactory实例”一节,该节讨论了如何注册HttpClient实例。

如果你想使用不同配置的HttpClient实例,以下是一个不错的选择。下面的代码片段说明了如何创建。

 
1
2
3
4
5
6
7
services.AddHttpClient("github", c =>
{
  c.BaseAddress = new Uri("https://api.github.com/");
  c.DefaultRequestHeaders.Add("Accept",
  "application/vnd.github.v3+json");
  c.DefaultRequestHeaders.Add("User-Agent""This is a test user agent");
});

第二种方法是使用包装了HttpClient实例的自定义类,该自定义类封装了通过HTTP协议调用所有终结点的逻辑。下面的代码片段说明了如何定义自定义HttpClient类。

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class ProductService : IProductService
{
  private IHttpClientFactory _httpClientFactory;
  private readonly HttpClient _httpClient;
  private readonly string _baseUrl = "http://localhost:1810/";
  public ProductService(HttpClient httpClient)
  {
    _httpClient = httpClient;
  }
  public async Task<Catalog> GetAllProducts()
  {
    _httpClient = _httpClientFactory.CreateClient();
    _httpClient.BaseAddress = new Uri(_baseUrl);
    var uri = "/api/products";
    var result = await _httpClient.GetStringAsync(uri);
    return JsonConvert.DeserializeObject<Product>(result);
  }
}

通过以下代码注册自定义的client:

1
services.AddHttpClient<IProductService, ProductService>();

 

 

将MessageHandler添加到命名管道中

 

MessageHandler是扩展自HttpMessageHandler类,它可以接受HTTP请求并返回HTTP响应。如果你想构建自己的MessageHandler,你应该创建一个继承DelegatingHandler的类。

你可以将HttpMessageHandler添加到请求处理管道中。可以在Startup类的ConfigureServices方法中使用以下代码将HttpMessageHandler添加到管道中。

 
1
2
3
4
5
6
7
8
9
public void ConfigureServices(IServiceCollection services)
{
  services.AddHttpClient("github", c =>
  {
    c.BaseAddress = new Uri("https://api.github.com/");
  })
  .AddHttpMessageHandler<DemoHandler>();
  services.AddTransient<DemoHandler>();
}

IHttpClientFactory是一个自.net Core 2.1以来就可用的工厂类。如果你使用IHttpClientFactory来创建HttpClient实例,那么底层HttpClientMessagehandler实例的池化和生命周期将自动管理。IHttpClientFactory还负责处理一些常见问题,比如日志记录。

 

 

 

控制台中使用HttpClientFactory

 

整体说明:这里主要是借助依赖注入程序,在控制台上获取需要的相关类,然后进行使用对应方法的调用

(1).首先需要添加依赖注入的程序集【Microsoft.Extensions.DependencyInjection】

(2).添加所需组件对应的程序集,并进行Addxxxx

(3).创建Provicder

(4).利用Provider调用GetService获取对应对象

 

1. HttpClientFactory

  添加程序集:【Microsoft.Extensions.Http】

 

{
                 var serviceCollection = new ServiceCollection();
                 serviceCollection.AddHttpClient();
                 var serviceProvider = serviceCollection.BuildServiceProvider();
                 //var serviceProvider = new ServiceCollection().AddHttpClient().BuildServiceProvider();  //等价于以上三句话
                 IHttpClientFactory httpClientFactory = serviceProvider.GetService<IHttpClientFactory>();
 
                 //下面是使用
                 string url2 = "http://XXX:8055/Home/SendAllMsg";
                 var client = httpClientFactory.CreateClient();
                 var content = new StringContent("msg=123", Encoding.UTF8, "application/x-www-form-urlencoded");
                 var response = client.PostAsync(url2, content).Result;
                 string result = "";
                 if (response.IsSuccessStatusCode)
                 {
                     result = response.Content.ReadAsStringAsync().Result;
                 }
             }

  


 

 

鸣谢:

https://juejin.cn/post/6930403240156594183

 http://t.zoukankan.com/yaopengfei-p-12122623.html

 

 

posted @ 2022-05-31 17:01  春光牛牛  阅读(2068)  评论(0编辑  收藏  举报