温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

ASP.NET Core怎么使用IHttpClientFactory发出HTTP请求

发布时间:2022-04-06 17:24:13 来源:亿速云 阅读:238 作者:iii 栏目:开发技术

今天小编给大家分享一下ASP.NET Core怎么使用IHttpClientFactory发出HTTP请求的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

1.HttpClient类使用存在的问题

HttpClient类的使用所存在的问题,百度搜索的文章一大堆,好多都是单纯文字描述,让人感觉不太好理解,为了更好理解HttpClient使用存在的问题,下面让我们通过代码跟示例来描述。

using(var client = new HttpClient())

传统关闭连接方法如上述代码所示,但当使用using语句释放HttpClient对象的时候,套接字(socket)也不会立即释放,下面我们通过请求aspnetmonsters站点的示例来验证下:

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Starting connections");
        var g = GetAsync();
        g.Wait();
        Console.WriteLine("Connections done");
        Console.ReadKey();
    }
    static async Task GetAsync()
    {
        for (int i = 0; i < 5; i++)
        {
            using (var client = new HttpClient())
            {
                var result = await client.GetAsync("http://aspnetmonsters.com/");
                Console.WriteLine(result.StatusCode);
            }
        }
    }
}

输出结果:

ASP.NET Core怎么使用IHttpClientFactory发出HTTP请求

控制台打印出五条请求站点返回状态的信息,下面我们通过netstat工具打印出五个请求连接套接字状态:

ASP.NET Core怎么使用IHttpClientFactory发出HTTP请求

应用程序已经运行结束了(结束连接),但是打印结果显示连接状态仍然是TIME_WAIT,也就是说在此状态期间仍然在观察是否有数据包进入连接(如果连接等待中有任何数据包仍然会通过),因为它们可能在某个地方被网络延迟。

ASP.NET Core怎么使用IHttpClientFactory发出HTTP请求

Windows将在此状态下保持连接240秒(由其设置[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\TcpTimedWaitDelay])。Windows可以快速打开新套接字的速度有限,因此如果您耗尽连接池,那么您可能会看到如下错误:

ASP.NET Core怎么使用IHttpClientFactory发出HTTP请求

而怎么做才可以减少套接字的浪费呢?我们在上述代码中把每次循环中创建的HttpClient对象拉到Main外定义为一个共享的静态实例:

class Program
{
    private static HttpClient client = new HttpClient();
    static void Main(string[] args)
    {
        Console.WriteLine("Starting connections");
        var g = GetAsync();
        g.Wait();
        Console.WriteLine("Connections done");
        Console.ReadKey();
    }
    static async Task GetAsync()
    {
        for (int i = 0; i < 5; i++)
        {
            var result = await client.GetAsync("http://aspnetmonsters.com/");
            Console.WriteLine(result.StatusCode);
        }
    }
}

应用程序运动完毕之后,我们再通过netstat工具打印出五个请求连接套接字状态,这时候会看到信息如下:

ASP.NET Core怎么使用IHttpClientFactory发出HTTP请求

通过共享一个实例,减少了套接字的浪费,实际上由于套接字重用而传输快一点。
总结:

  • 在创建HttpClient实例的时候,最好是静态(static )实例。

  • 不要用using包装HttpClient对象。

在.NET Core 2.1版本之后引入的 HttpClientFactory解决了HttpClient的所有痛点。有了 HttpClientFactory,我们不需要关心如何创建HttpClient,又如何释放它。通过它可以创建具有特定业务的HttpClient,而且可以很友好的和 DI 容器结合使用,更为灵活。下面以 ASP.NET Core为例介绍HttpClientFactory的四种使用方式。

2.HttpClientFactory 的多种使用方式

可以通过多种使用方式在应用程序中使用HttpClientFactory。

2.1使用基本用法

在Startup.ConfigureServices方法中,通过在IServiceCollection上调用AddHttpClient扩展方法可以注册IHttpClientFactory服务。
services.AddHttpClient();
注册服务后,我们新建BasicUsageModel类使用IHttpClientFactory创建HttpClient实例:

public class BasicUsageModel
{
    private readonly IHttpClientFactory _clientFactory;
    public IEnumerable<GitHubBranch> Branches { get; private set; }
    public bool GetBranchesError { get; private set; }
    public BasicUsageModel(IHttpClientFactory clientFactory)
    {
        _clientFactory = clientFactory;
    }
    public async Task OnGet()
    {
        var request = new HttpRequestMessage(HttpMethod.Get,
            "https://api.github.com/repos/aspnet/AspNetCore.Docs/branches");
        request.Headers.Add("Accept", "application/vnd.github.v3+json");
        request.Headers.Add("User-Agent", "HttpClientFactory-Sample");
        var client = _clientFactory.CreateClient();
        var response = await client.SendAsync(request);
        if (response.IsSuccessStatusCode)
        {
            Branches = await response.Content
                .ReadAsAsync<IEnumerable<GitHubBranch>>();
        }
        else
        {
            GetBranchesError = true;
            Branches = Array.Empty<GitHubBranch>();
        }
    }
}
public class GitHubBranch
{
    public string name { get; set; }
}

以这种方式直接在使用IHttpClientFactory的类中调用CreateClient方法创建HttpClient实例。然后在Controller中调用BasicUsageModel类:

public class HomeController : Controller
{
    private readonly IHttpClientFactory _clientFactory;
    public HomeController(IHttpClientFactory clientFactory)
    {
        _clientFactory = clientFactory;
    }
    public IActionResult Index()
    {
        BasicUsageModel model = new BasicUsageModel(_clientFactory);
        var task = model.OnGet();
        task.Wait();
        List<GitHubBranch> list = model.Branches.ToList();
        return View(list);
    }
}

2.2使用命名客户端

如果应用程序需要有许多不同的HttpClient用法(每种用法的服务配置都不同),可以视情况使用命名客户端。可以在HttpClient中注册时指定命名Startup.ConfigureServices的配置。

services.AddHttpClient("github", c =>
{
    c.BaseAddress = new Uri("https://api.github.com/");
    // Github API versioning
    c.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json");
    // Github requires a user-agent
    c.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactory-Sample");
});

上面的代码调用AddHttpClient,同时提供名称“github”。此客户端应用了一些默认配置,也就是需要基址和两个标头来使用GitHub API。每次调用CreateClient时,都会创建HttpClient 的新实例,并调用配置操作。要使用命名客户端,可将字符串参数传递到CreateClient。指定要创建的客户端的名称:

public class NamedClientModel : PageModel
{
    private readonly IHttpClientFactory _clientFactory;
    public IEnumerable<GitHubPullRequest> PullRequests { get; private set; }
    public bool GetPullRequestsError { get; private set; }
    public bool HasPullRequests => PullRequests.Any();
    public NamedClientModel(IHttpClientFactory clientFactory)
    {
        _clientFactory = clientFactory;
    }
    public async Task OnGet()
    {
        var request = new HttpRequestMessage(HttpMethod.Get,
            "repos/aspnet/AspNetCore.Docs/pulls");
        var client = _clientFactory.CreateClient("github");
        var response = await client.SendAsync(request);
        if (response.IsSuccessStatusCode)
        {
            PullRequests = await response.Content
                .ReadAsAsync<IEnumerable<GitHubPullRequest>>();
        }
        else
        {
            GetPullRequestsError = true;
            PullRequests = Array.Empty<GitHubPullRequest>();
        }
    }
}
public class GitHubPullRequest
{
    public string url { get; set; }
    public int? id { get; set; }
    public string node_id { get; set; }
}

在上述代码中,请求不需要指定主机名。可以仅传递路径,因为采用了为客户端配置的基址。在Controller中调用方法如上个示例。

2.3使用类型化客户端

什么是“类型化客户端”?它只是DefaultHttpClientFactory注入时配置的HttpClient。
下图显示了如何将类型化客户端与HttpClientFactory结合使用:

ASP.NET Core怎么使用IHttpClientFactory发出HTTP请求

类型化客户端提供与命名客户端一样的功能,不需要将字符串用作密钥。它们提供单个地址来配置特定HttpClient并与其进行交互。例如,单个类型化客户端可能用于单个后端终结点,并封装此终结点的所有处理逻辑。另一个优势是它们使用 DI 且可以被注入到应用中需要的位置。
类型化客户端在构造函数中接收HttpClient参数:

public class GitHubService
{
    public HttpClient Client { get; }
    public GitHubService(HttpClient client)
    {
        client.BaseAddress = new Uri("https://api.github.com/");
        // GitHub API versioning
        client.DefaultRequestHeaders.Add("Accept",
            "application/vnd.github.v3+json");
        // GitHub requires a user-agent
        client.DefaultRequestHeaders.Add("User-Agent",
            "HttpClientFactory-Sample");
        Client = client;
    }
    public async Task<IEnumerable<GitHubIssue>> GetAspNetDocsIssues()
    {
        var response = await Client.GetAsync(
"/repos/aspnet/AspNetCore.Docs/issues?state=open&sort=created&direction=desc");
        response.EnsureSuccessStatusCode();
        var result = await response.Content
            .ReadAsAsync<IEnumerable<GitHubIssue>>();
        return result;
    }
}
public class GitHubIssue
{
    public string url { get; set; }
    public int? id { get; set; }
    public string node_id { get; set; }
}

在上述代码中,配置转移到了类型化客户端中。HttpClient对象公开为公共属性。可以定义公开HttpClient功能的特定于API的方法。GetAspNetDocsIssues方法从GitHub存储库封装查询和分析最新待解决问题所需的代码。
要注册类型化客户端,可在Startup.ConfigureServices中使用通用的AddHttpClient扩展方法,指定类型化客户端类:

services.AddHttpClient<GitHubService>();

使用DI将类型客户端注册为暂时客户端。可以直接插入或使用类型化客户端:

public class TypedClientModel : PageModel
{
    private readonly GitHubService _gitHubService;
    public IEnumerable<GitHubIssue> LatestIssues { get; private set; }
    public bool HasIssue => LatestIssues.Any();
    public bool GetIssuesError { get; private set; }
    public TypedClientModel(GitHubService gitHubService)
    {
        _gitHubService = gitHubService;
    }
    public async Task OnGet()
    {
        try
        {
            LatestIssues = await _gitHubService.GetAspNetDocsIssues();
        }
        catch (HttpRequestException)
        {
            GetIssuesError = true;
            LatestIssues = Array.Empty<GitHubIssue>();
        }
    }
}

以上就是“ASP.NET Core怎么使用IHttpClientFactory发出HTTP请求”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注亿速云行业资讯频道。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI