{ "cells": [ { "cell_type": "markdown", "metadata": { "dotnet_interactive": { "language": "csharp" }, "polyglot_notebook": { "kernelName": "csharp" } }, "source": [ "# HttpClient 初始化与生命周期管理" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "HttpClient 旨在实例化一次,并在应用程序的整个生命周期内重复使用。\n", "\n", "为实现复用,HttpClient类库默认使用连接池和请求管道,可以手动管理(连接池、配置管道、使用Polly); 结合IoC容器、工厂模式(提供了IHttpClientFactory类库)、复原库Polly,可以更加方便、完善的使用,这也是推荐的方法。" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "dotnet_interactive": { "language": "csharp" }, "polyglot_notebook": { "kernelName": "csharp" }, "vscode": { "languageId": "polyglot-notebook" } }, "outputs": [], "source": [ "//全局设置,行运行一次,为后续准备\n", "#r \"nuget:System.Net.Http.Json\"\n", "#r \"nuget:Microsoft.Extensions.DependencyInjection\"\n", "#r \"./Publish/HttpClientStudy.Core/HttpClientStudy.Core.dll\"\n", "\n", "global using System.Net.Http;\n", "global using System.Net.Http.Headers;\n", "global using HttpClientStudy.Config;\n", "global using HttpClientStudy.Core;\n", "global using HttpClientStudy.Core.Utilities;\n", "\n", "//启动已发布的WebApi项目\n", "Console.WriteLine(\"启动WebApi项目\");\n", "var startMessage = DotnetCommondUtility.ExecuteCommand(\"exec\",\"./Publish/HttpClientStudy.WebApp/HttpClientStudy.WebApp.dll\");\n", "Console.WriteLine(startMessage);\n" ] }, { "cell_type": "markdown", "metadata": { "dotnet_interactive": { "language": "csharp" }, "polyglot_notebook": { "kernelName": "csharp" }, "vscode": { "languageId": "polyglot-notebook" } }, "source": [ "## 1、手动管理:直接实例化-强烈不推荐" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "下面这种每次使用都实例化的用法是最常见、最`不推荐的`:\n", "\n", "因为HttpClient刚推出时不成熟及微软官方文档的示例代码是这种用法,再加上这种是最简单方便的使用方法,就造成很多人使用这种用法。\n", "这种方法有如下缺点:\n", "+ 1. 每次使用都实例化,造成性能开销大、容易内存泄露;\n", "+ 2. 并发量大、请求频繁时:网络端口会被耗尽 `Using包HttpClient,也只是在应用进程中释放了HttpClient实例,但http请求/响应是跨操作系统和网络的,而系统及网络问题在进程之上,不是进程所能处理的。`\n", " \n", "优点:\n", "+ 1. 使用简单,好学易用;\n", "+ 2. 并发量小且请求不频繁时,问题不大;" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "dotnet_interactive": { "language": "csharp" }, "polyglot_notebook": { "kernelName": "csharp" }, "vscode": { "languageId": "polyglot-notebook" } }, "outputs": [], "source": [ "/*\n", " 每次请求都实例化:并发量大、请求频繁进会耗尽套接字端口\n", "*/\n", "{ \n", " using(var client = new HttpClient())\n", " {\n", " //发送请求\n", " var response = await client.GetAsync(\"http://localhost\");\n", " response.EnsureSuccessStatusCode();\n", " }\n", "\n", " //显示句柄\n", " var displayValue = display($\"第 1 次请求,成功!\");\n", "\n", " for(int i=0;i<10;i++)\n", " {\n", " using(var client = new HttpClient())\n", " {\n", " var response = await client.GetAsync(\"http://localhost\");\n", " response.EnsureSuccessStatusCode();\n", " displayValue.Update($\"第 {i+1} 次/ 共 10 次请求,成功!\");\n", " }\n", " }\n", "}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 2、手动管理:静态类或单例" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 3、手动管理:多工具类(每类请求对应一种工具类或单例类)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 4、手动管理:可复原(Polly)请求" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 5、IoC容器管理:类型化的客户端" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 6、客户端工厂管理:IHttpClientFactory(需要结合IoC)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 7、综合管理:工厂 + 类型化客户端 + 请求管道 + Polly(默认使用 连接池和IoC容器)" ] } ], "metadata": { "kernelspec": { "display_name": ".NET (C#)", "language": "C#", "name": ".net-csharp" }, "language_info": { "name": "python" }, "polyglot_notebook": { "kernelInfo": { "defaultKernelName": "csharp", "items": [ { "aliases": [], "name": "csharp" } ] } } }, "nbformat": 4, "nbformat_minor": 2 }