Asp.Net Core2.1前后使用HttpClient的两种方式

秋天是沉甸甸的季节,秋天是收获的季节。秋天,写着收获,秋天,写着相思。秋天,比冬天更有生机勃勃的景象,白雪皑皑的冬天固然可爱,但是,瓜果飘香的金秋却更富有灿烂绚丽的色彩。

前言

在.Net Core应用开发中,调用第三方接口也是常有的事情,HttpClient使用人数、使用频率算是最高的一种了,在.Net Core中,HttpClient的使用方式随着版本的升级也发生了一些变化,本次就讲解一下Asp.Net Core2.1前后使用的两种方式。

一、原先HttpClient使用方式

一般来讲,喜欢要用的时候才会选择去获取资源,因此,当在有需求时才会用HttpClient去调用资源,便会使用如下这种方式或其它方式获取资源。

//do something...
using (var httpClient = new HttpClient())
{
 var requestUri = "http://aspnetcore.online/api/resource/getresource";
 var httpResponseMessage = await httpClient.GetAsync(requestUri);
 //do something...

 return Ok(httpResponseMessage);
}

如果可以正常访问目标地址的话,则会返回相应的资源信息。  

又如Post方式提交并返回相应的内容,都是可以直接使用。

//do something...
using (var httpClient = new HttpClient())
{
 var requestUri = "http://aspnetcore.online/api/resource/postresource";
 var httpResponseMessage = await httpClient.PostAsJsonAsync(requestUri,"星城软件");
 //do something...

 return Ok(httpResponseMessage);
}

但是这种情况下会出现一个严重的问题,在不停的调用情形下,tcp连接数会被耗尽,虽然使用using方式调用HttpClient并在退出前调用Dispose()方法将HttpClient释放了,但是tcp连接仍然处于保持状态,在240s后才会自动断开,这里就涉及到一个连接状态了,首先得理解下http的工作原理,http协议是建立在tcp协议基础之上,当浏览器需要从服务器获取数据的时候,会发出一次http请求。http会通过tcp建立起一个到服务器的连接通道,当本次请求需要的数据完毕后,http会立即将tcp连接断开,这个过程是很短的。所以http连接是一种短连接,是一种无状态的连接。但是tcp的连接只要我们不通过代码把连接关闭,这个连接就会在客户端和服务端的进程中一直存在,相关状态数据会一直保存着,直到无响应状态持续了默认关闭时间后自动断开。

  

当短期请求量过大时,这就可能导致了"套接字资源耗尽异常",因此,为了解决这个问题,想到不释放HttpClient,将它作为单例一直使用,实现单例方式有很多种。

如使用单例模式,只生成一个HttpClient

private static HttpClient _httpClient = null;
public HttpClient CreateHttpClient()
{
 if (_httpClient == null) _httpClient = new HttpClient();
 return _httpClient;
}

亦或是在初始化时完成单例注入,创建一个IHttpClient接口,及相应的实现StandardHttpClient,实现类种加入HttpClient属性,在实现类构造函数中完成初始化后便可直接使用该实现类完成资源请求工作。

//在startup中完成单例注入
services.AddSingleton<IHttpClient, StandardHttpClient>();

public interface IHttpClient
{
 //do something
}

public class StandardHttpClient : IHttpClient
{
 private HttpClient _client;

 public StandardHttpClient()
 {
 _client = new HttpClient();
 }

 //do something...
}

虽然这样解决了"套接字资源耗尽异常",但是又带来了新的问题,熬不过DNS生存时间(TTL),当主机 DNS 更新时,又可能产生异常,提示无法解析主机名称,因为单例HttpClient不会随着主机DNS更新而更新,Singleton HttpClient doesn't respect DNS changes。

An error occurred while sending the request. Couldn't resolve host name An error occurred while sending the request. Couldn't resolve host name

二、现有HttpClient使用方式

在.Net Core2.1后,微软引入了HttpClientFactory彻底解决这个问题,工厂模式的职责是负责创建对象,这个类主要负责创建HttpClient实例

首先在StartUp中注册,可能会提示安装这个Nuget包

 services.AddHttpClient();

该方法内部实现过程可以浏览:https://www.haodaima.com/article/157254.htm

其次,在需要使用时,使用构造函数注入即可

[Route("api/[controller]")]
[ApiController]
public class HttpClientController : ControllerBase
{
 IHttpClientFactory _httpClientFactory;

 public HttpClientController(IHttpClientFactory httpClientFactory)
 {
 _httpClientFactory = httpClientFactory;
 }

 [HttpGet]
 [Route(nameof(Index))]
 public async Task<IActionResult> Index()
 {
 var client = _httpClientFactory.CreateClient();
 var result = await client.GetAsync("http://aspnetcore.online/api/resource/getresource");
 return Ok(result);
 }
}

具体实现原理简述为:HttpClientFactory内部管理着一个连接句柄池,对每一个HttpClient使用一个句柄进行跟踪管理,当该实例使用完毕后,句柄仍然控制资源释放,在短期大量处理时,可以将这部分句柄完成对不同实例的跟踪管理,使得句柄,也就是相应的套接字生命周期延长,对套接字完成了复用。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。

您可能有感兴趣的文章
详解ASP.NET MVC 下拉框的传值的两种方式

ASP.NET中Response.BufferOutput属性的使用技巧

ASP.NET轻量级MVC框架Nancy的基本用法

ASP.NET Core中的对象池介绍

.NET集成ORM框架HiSql