You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
HttpClientStudy/Docs/1.3.0.基础使用.管理客户端.ipynb

764 lines
28 KiB
Plaintext

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

{
"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": 1,
"metadata": {
"dotnet_interactive": {
"language": "csharp"
},
"polyglot_notebook": {
"kernelName": "csharp"
},
"vscode": {
"languageId": "polyglot-notebook"
}
},
"outputs": [
{
"data": {
"text/html": [
"<div><div></div><div></div><div><strong>Installed Packages</strong><ul><li><span>Microsoft.Extensions.DependencyInjection, 8.0.0</span></li><li><span>System.Net.Http.Json, 8.0.0</span></li></ul></div></div>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"启动WebApi项目\r\n"
]
},
{
"data": {
"text/plain": [
"d:\\软件项目\\学习项目\\HttpClientStudy\\Docs\\Publish\\HttpClientStudy.WebApp\\HttpClientStudy.WebApp.exe"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"程序[d:\\软件项目\\学习项目\\HttpClientStudy\\Docs\\Publish\\HttpClientStudy.WebApp\\HttpClientStudy.WebApp.exe]已在新的命令行窗口执行。如果未出现新命令行窗口,可能是程序错误造成窗口闪现!\r\n"
]
}
],
"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 workDir = Environment.CurrentDirectory;\n",
"var fullPath = System.IO.Path.GetFullPath(\"./Publish/HttpClientStudy.WebApp/HttpClientStudy.WebApp.exe\", workDir);\n",
"fullPath.Display();\n",
"var startMessage = AppUtility.RunWebApiExeFile(fullPath);\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": 2,
"metadata": {
"dotnet_interactive": {
"language": "csharp"
},
"polyglot_notebook": {
"kernelName": "csharp"
},
"vscode": {
"languageId": "polyglot-notebook"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"配置文件根目录d:\\软件项目\\学习项目\\HttpClientStudy\\Docs\\Publish\\HttpClientStudy.Core\r\n"
]
},
{
"data": {
"text/plain": [
"第 10 次/ 共 10 次请求,成功!"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"/*\n",
" 每次请求都实例化:并发量大、请求频繁进会耗尽套接字端口\n",
"*/\n",
"{ \n",
" var baseUrl = WebApiConfigManager.GetWebApiConfig().BaseUrl;\n",
"\n",
" using(var client = new HttpClient())\n",
" {\n",
" //发送请求\n",
" var response = await client.GetAsync(baseUrl);\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(baseUrl);\n",
" response.EnsureSuccessStatusCode();\n",
" displayValue.Update($\"第 {i+1} 次/ 共 10 次请求,成功!\");\n",
" }\n",
" }\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 2、手动管理静态类或单例"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"相比于直接new,实现了HttpClient的重用`不推荐的`\n",
"\n",
"缺点:\n",
" 1. 不够灵活、优雅:特别是有多个系列的请求时;\n",
" \n",
"优点:\n",
" 1. 复用 HttpClient\n",
" 2. 实现了HttpClient的重用减少创建和销毁的开销"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"dotnet_interactive": {
"language": "csharp"
},
"polyglot_notebook": {
"kernelName": "csharp"
},
"vscode": {
"languageId": "polyglot-notebook"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"配置文件根目录d:\\软件项目\\学习项目\\HttpClientStudy\\Docs\\Publish\\HttpClientStudy.Core\n",
"{\"data\":{\"host\":\"localhost\",\"port\":5189,\"scheme\":\"http\",\"pathBase\":\"\",\"baseUrl\":\"http://localhost:5189\",\"webAppMutexName\":\"HttpClientStudy.WebApp\"},\"code\":1,\"message\":\"成功\"}\n",
"{\"data\":[{\"id\":1,\"name\":\"管理员01\",\"password\":\"123456\",\"role\":\"Admin\"},{\"id\":2,\"name\":\"管理员02\",\"password\":\"123456\",\"role\":\"Admin\"},{\"id\":3,\"name\":\"管理员03\",\"password\":\"123456\",\"role\":\"Admin\"},{\"id\":4,\"name\":\"管理员04\",\"password\":\"123456\",\"role\":\"Admin\"},{\"id\":5,\"name\":\"管理员05\",\"password\":\"123456\",\"role\":\"Admin\"},{\"id\":6,\"name\":\"管理员06\",\"password\":\"123456\",\"role\":\"Admin\"},{\"id\":7,\"name\":\"管理员07\",\"password\":\"123456\",\"role\":\"Admin\"},{\"id\":8,\"name\":\"管理员08\",\"password\":\"123456\",\"role\":\"Admin\"},{\"id\":9,\"name\":\"管理员09\",\"password\":\"123456\",\"role\":\"Admin\"},{\"id\":10,\"name\":\"管理员10\",\"password\":\"123456\",\"role\":\"Admin\"},{\"id\":11,\"name\":\"开发01\",\"password\":\"123456\",\"role\":\"Dev\"},{\"id\":12,\"name\":\"开发01\",\"password\":\"123456\",\"role\":\"Dev\"},{\"id\":13,\"name\":\"开发03\",\"password\":\"123456\",\"role\":\"Dev\"},{\"id\":14,\"name\":\"开发04\",\"password\":\"123456\",\"role\":\"Dev\"},{\"id\":15,\"name\":\"开发05\",\"password\":\"123456\",\"role\":\"Dev\"},{\"id\":16,\"name\":\"开发06\",\"password\":\"123456\",\"role\":\"Dev\"},{\"id\":17,\"name\":\"开发07\",\"password\":\"123456\",\"role\":\"Dev\"},{\"id\":18,\"name\":\"开发08\",\"password\":\"123456\",\"role\":\"Dev\"},{\"id\":19,\"name\":\"开发09\",\"password\":\"123456\",\"role\":\"Dev\"},{\"id\":20,\"name\":\"开发10\",\"password\":\"123456\",\"role\":\"Dev\"}],\"code\":1,\"message\":\"成功\"}\n"
]
}
],
"source": [
"/*\n",
" 静态类/属性\n",
"*/\n",
"\n",
"public class HttpClientHelper\n",
"{\n",
" public readonly static HttpClient StaticClient;\n",
"\n",
" static HttpClientHelper()\n",
" {\n",
" SocketsHttpHandler handler = new SocketsHttpHandler()\n",
" {\n",
" PooledConnectionLifetime = TimeSpan.FromSeconds(30),\n",
" };\n",
"\n",
" StaticClient = new HttpClient(handler);\n",
"\n",
" //统一设置:请求头等\n",
"\n",
" //统一错误处理\n",
"\n",
" //当然这里也可以设置Pipline不过这里就不演示了\n",
" } \n",
"\n",
" public static async Task<HttpResponseMessage> GetAsync(string url)\n",
" {\n",
" return await StaticClient.GetAsync(url);\n",
" }\n",
"\n",
" public static async Task<string> GetStringAsync(string url)\n",
" {\n",
" var response = await StaticClient.GetAsync(url);\n",
" response.EnsureSuccessStatusCode();\n",
" return await response.Content.ReadAsStringAsync();\n",
" }\n",
"\n",
" public static async Task<HttpResponseMessage> PostAsync(string url, HttpContent content)\n",
" {\n",
" return await StaticClient.PostAsync(url, content);\n",
" }\n",
"}\n",
"\n",
"{ //调用静态类\n",
" var baseUrl = WebApiConfigManager.GetWebApiConfig().BaseUrl;\n",
" var response = await HttpClientHelper.GetAsync(baseUrl+\"/api/Config/GetApiConfig\");\n",
" var content = await response.Content.ReadAsStringAsync();\n",
" Console.WriteLine(content);\n",
"\n",
" var response2 = await HttpClientHelper.GetStringAsync(baseUrl+\"/api/Normal/GetAllAccounts\");\n",
" Console.WriteLine(response2);\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"dotnet_interactive": {
"language": "csharp"
},
"polyglot_notebook": {
"kernelName": "csharp"
},
"vscode": {
"languageId": "polyglot-notebook"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"配置文件根目录d:\\软件项目\\学习项目\\HttpClientStudy\\Docs\\Publish\\HttpClientStudy.Core\n",
"HttpClientSingleton 初始化一次\n",
"{\"data\":{\"host\":\"localhost\",\"port\":5189,\"scheme\":\"http\",\"pathBase\":\"\",\"baseUrl\":\"http://localhost:5189\",\"webAppMutexName\":\"HttpClientStudy.WebApp\"},\"code\":1,\"message\":\"成功\"}\n",
"{\"data\":[{\"id\":1,\"name\":\"管理员01\",\"password\":\"123456\",\"role\":\"Admin\"},{\"id\":2,\"name\":\"管理员02\",\"password\":\"123456\",\"role\":\"Admin\"},{\"id\":3,\"name\":\"管理员03\",\"password\":\"123456\",\"role\":\"Admin\"},{\"id\":4,\"name\":\"管理员04\",\"password\":\"123456\",\"role\":\"Admin\"},{\"id\":5,\"name\":\"管理员05\",\"password\":\"123456\",\"role\":\"Admin\"},{\"id\":6,\"name\":\"管理员06\",\"password\":\"123456\",\"role\":\"Admin\"},{\"id\":7,\"name\":\"管理员07\",\"password\":\"123456\",\"role\":\"Admin\"},{\"id\":8,\"name\":\"管理员08\",\"password\":\"123456\",\"role\":\"Admin\"},{\"id\":9,\"name\":\"管理员09\",\"password\":\"123456\",\"role\":\"Admin\"},{\"id\":10,\"name\":\"管理员10\",\"password\":\"123456\",\"role\":\"Admin\"},{\"id\":11,\"name\":\"开发01\",\"password\":\"123456\",\"role\":\"Dev\"},{\"id\":12,\"name\":\"开发01\",\"password\":\"123456\",\"role\":\"Dev\"},{\"id\":13,\"name\":\"开发03\",\"password\":\"123456\",\"role\":\"Dev\"},{\"id\":14,\"name\":\"开发04\",\"password\":\"123456\",\"role\":\"Dev\"},{\"id\":15,\"name\":\"开发05\",\"password\":\"123456\",\"role\":\"Dev\"},{\"id\":16,\"name\":\"开发06\",\"password\":\"123456\",\"role\":\"Dev\"},{\"id\":17,\"name\":\"开发07\",\"password\":\"123456\",\"role\":\"Dev\"},{\"id\":18,\"name\":\"开发08\",\"password\":\"123456\",\"role\":\"Dev\"},{\"id\":19,\"name\":\"开发09\",\"password\":\"123456\",\"role\":\"Dev\"},{\"id\":20,\"name\":\"开发10\",\"password\":\"123456\",\"role\":\"Dev\"}],\"code\":1,\"message\":\"成功\"}\n"
]
}
],
"source": [
"/*\n",
" 单例实现1:\n",
" 1. 私有构造函数,防止外部实例化\n",
" 2. 使用静态只读变量存储类的实例,由.Net框架保证实例不变且线程安全\n",
" 3. 密封类,拒绝继承,保证不被子类破坏\n",
"*/\n",
"\n",
"// 使用Lazy<T>实现单例\n",
"public sealed class HttpClientSingleton \n",
"{\n",
" // 私有静态变量,用于存储类的实例\n",
" private static readonly HttpClientSingleton instance = new HttpClientSingleton();\n",
" \n",
" //公共静态属性,用于获取类的实例\n",
" public static HttpClientSingleton Instance\n",
" {\n",
" get\n",
" {\n",
" return instance;\n",
" }\n",
" }\n",
"\n",
" private readonly HttpClient Client;\n",
"\n",
" //私有构造函数,防止外部实例化\n",
" private HttpClientSingleton() \n",
" {\n",
" SocketsHttpHandler handler = new SocketsHttpHandler()\n",
" {\n",
" PooledConnectionLifetime = TimeSpan.FromSeconds(30),\n",
" };\n",
"\n",
" Client = new HttpClient(handler);\n",
"\n",
" //统一设置:请求头等\n",
"\n",
" //统一错误处理\n",
"\n",
" //可以使用IoC容器来管理\n",
"\n",
" //当然这里也可以设置Pipline不过这里就不演示了\n",
" Console.WriteLine(\"HttpClientSingleton 初始化一次\");\n",
" }\n",
"\n",
" public async Task<HttpResponseMessage> GetAsync(string url)\n",
" {\n",
" return await Client.GetAsync(url);\n",
" }\n",
"\n",
" public async Task<string> GetStringAsync(string url)\n",
" {\n",
" var response = await Client.GetAsync(url);\n",
" response.EnsureSuccessStatusCode();\n",
" return await response.Content.ReadAsStringAsync();\n",
" }\n",
"}\n",
"\n",
"{ //调用示例\n",
"\n",
" var baseUrl = WebApiConfigManager.GetWebApiConfig().BaseUrl;\n",
" var response = await HttpClientSingleton.Instance.GetAsync(baseUrl+\"/api/Config/GetApiConfig\");\n",
" var content = await response.Content.ReadAsStringAsync();\n",
" Console.WriteLine(content);\n",
"\n",
" var response2 = await HttpClientSingleton.Instance.GetStringAsync(baseUrl+\"/api/Normal/GetAllAccounts\");\n",
" Console.WriteLine(response2);\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"dotnet_interactive": {
"language": "csharp"
},
"polyglot_notebook": {
"kernelName": "csharp"
},
"vscode": {
"languageId": "polyglot-notebook"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"配置文件根目录d:\\软件项目\\学习项目\\HttpClientStudy\\Docs\\Publish\\HttpClientStudy.Core\n",
"HttpClientSingleton2 初始化一次\n",
"{\"data\":{\"host\":\"localhost\",\"port\":5189,\"scheme\":\"http\",\"pathBase\":\"\",\"baseUrl\":\"http://localhost:5189\",\"webAppMutexName\":\"HttpClientStudy.WebApp\"},\"code\":1,\"message\":\"成功\"}\n",
"{\"data\":[{\"id\":1,\"name\":\"管理员01\",\"password\":\"123456\",\"role\":\"Admin\"},{\"id\":2,\"name\":\"管理员02\",\"password\":\"123456\",\"role\":\"Admin\"},{\"id\":3,\"name\":\"管理员03\",\"password\":\"123456\",\"role\":\"Admin\"},{\"id\":4,\"name\":\"管理员04\",\"password\":\"123456\",\"role\":\"Admin\"},{\"id\":5,\"name\":\"管理员05\",\"password\":\"123456\",\"role\":\"Admin\"},{\"id\":6,\"name\":\"管理员06\",\"password\":\"123456\",\"role\":\"Admin\"},{\"id\":7,\"name\":\"管理员07\",\"password\":\"123456\",\"role\":\"Admin\"},{\"id\":8,\"name\":\"管理员08\",\"password\":\"123456\",\"role\":\"Admin\"},{\"id\":9,\"name\":\"管理员09\",\"password\":\"123456\",\"role\":\"Admin\"},{\"id\":10,\"name\":\"管理员10\",\"password\":\"123456\",\"role\":\"Admin\"},{\"id\":11,\"name\":\"开发01\",\"password\":\"123456\",\"role\":\"Dev\"},{\"id\":12,\"name\":\"开发01\",\"password\":\"123456\",\"role\":\"Dev\"},{\"id\":13,\"name\":\"开发03\",\"password\":\"123456\",\"role\":\"Dev\"},{\"id\":14,\"name\":\"开发04\",\"password\":\"123456\",\"role\":\"Dev\"},{\"id\":15,\"name\":\"开发05\",\"password\":\"123456\",\"role\":\"Dev\"},{\"id\":16,\"name\":\"开发06\",\"password\":\"123456\",\"role\":\"Dev\"},{\"id\":17,\"name\":\"开发07\",\"password\":\"123456\",\"role\":\"Dev\"},{\"id\":18,\"name\":\"开发08\",\"password\":\"123456\",\"role\":\"Dev\"},{\"id\":19,\"name\":\"开发09\",\"password\":\"123456\",\"role\":\"Dev\"},{\"id\":20,\"name\":\"开发10\",\"password\":\"123456\",\"role\":\"Dev\"}],\"code\":1,\"message\":\"成功\"}\n"
]
}
],
"source": [
"/*\n",
" 单例实现2:\n",
" 1. 私有构造函数,防止外部实例化\n",
" 2. 使用Lazy<T>, 延迟实例化, 由.Net 框架保证线程安全\n",
" 3. 密封类,拒绝继承,保证不被子类破坏\n",
"*/\n",
"\n",
"// 由于静态初始化器是由 .NET 运行时在后台处理的,因此它是线程安全的,不需要额外的锁定机制。\n",
"public sealed class HttpClientSingleton2\n",
"{\n",
" private static readonly Lazy<HttpClient> _httpClientLazy = new Lazy<HttpClient>(() =>\n",
" {\n",
" SocketsHttpHandler handler = new SocketsHttpHandler()\n",
" {\n",
" PooledConnectionLifetime = TimeSpan.FromSeconds(30)\n",
" };\n",
"\n",
" var client = new HttpClient(handler)\n",
" {\n",
" // 可以在这里配置HttpClient的实例例如设置超时时间、基地址等\n",
" //Timeout = TimeSpan.FromSeconds(30),\n",
" //BaseAddress = new Uri(\"https://api.example.com/\"),\n",
" };\n",
"\n",
"\n",
" //统一设置:请求头等\n",
"\n",
" //统一错误处理\n",
"\n",
" //可以使用IoC容器来管理\n",
"\n",
" //当然这里也可以设置Pipline不过这里就不演示了\n",
" Console.WriteLine(\"HttpClientSingleton2 初始化一次\");\n",
"\n",
" return client;\n",
" });\n",
"\n",
" public static HttpClient Instance => _httpClientLazy.Value;\n",
"\n",
" // 私有构造函数,防止外部实例化\n",
" private HttpClientSingleton2() { } \n",
"\n",
" public async Task<HttpResponseMessage> GetAsync(string url)\n",
" {\n",
" return await _httpClientLazy.Value.GetAsync(url);\n",
" }\n",
"\n",
" public async Task<string> GetStringAsync(string url)\n",
" {\n",
" var response = await _httpClientLazy.Value.GetAsync(url);\n",
" response.EnsureSuccessStatusCode();\n",
" return await response.Content.ReadAsStringAsync();\n",
" }\n",
"}\n",
"\n",
"{ //调用示例\n",
"\n",
" var baseUrl = WebApiConfigManager.GetWebApiConfig().BaseUrl;\n",
" var response = await HttpClientSingleton2.Instance.GetAsync(baseUrl+\"/api/Config/GetApiConfig\");\n",
" var content = await response.Content.ReadAsStringAsync();\n",
" Console.WriteLine(content);\n",
"\n",
" var response2 = await HttpClientSingleton2.Instance.GetStringAsync(baseUrl+\"/api/Normal/GetAllAccounts\");\n",
" Console.WriteLine(response2);\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 3、手动管理多工具类(每类请求对应一种工具类或单例类)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"把不同类别的请求分成不同的工具类,业务类直接封装成工具类的方法。类似类型化的客户端。 简单使用的话,`比较推荐`\n",
"\n",
"优点:\n",
" 1. 复用HttpClient\n",
" 2. 可以灵活的进行统一配置\n",
" 3. 不同类别不同工具类,方便定制\n",
" 4. 业务直接封装成工具类方法,调用方便、快捷\n",
"\n",
"缺点:\n",
" 1. 工具类比较多,需要手动维护\n",
" 2. 工具类方法比较多且和业务直接相关,需要手动维护\n"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"dotnet_interactive": {
"language": "csharp"
},
"polyglot_notebook": {
"kernelName": "csharp"
},
"vscode": {
"languageId": "polyglot-notebook"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"401173\r\n"
]
}
],
"source": [
"// 百度服务类\n",
"public sealed class BaiduService \n",
"{\n",
" private readonly HttpClient _httpClient;\n",
" public BaiduService()\n",
" {\n",
" //初始化httpClient\n",
" var baseHander = new SocketsHttpHandler() \n",
" { \n",
" MaxConnectionsPerServer = 1000 \n",
" };\n",
"\n",
" _httpClient = new HttpClient(baseHander)\n",
" {\n",
" Timeout = TimeSpan.FromSeconds(10),\n",
" BaseAddress = new Uri(\"http://www.baidu.com\"),\n",
" };\n",
" }\n",
"\n",
" ///// <summary>\n",
" /// 获取百度首页长度\n",
" /// </summary>\n",
" public async Task<int> GetIndexLengthAsync(string url)\n",
" {\n",
" var response = await _httpClient.GetAsync(url);\n",
" response.EnsureSuccessStatusCode();\n",
" var result = await response.Content.ReadAsStringAsync();\n",
" return result.Length;\n",
" }\n",
"}\n",
"//调用示例\n",
"{\n",
" var service = new BaiduService();\n",
" var result = await service.GetIndexLengthAsync(\"/\");\n",
" Console.WriteLine(result);\n",
"}"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"dotnet_interactive": {
"language": "csharp"
},
"polyglot_notebook": {
"kernelName": "csharp"
},
"vscode": {
"languageId": "polyglot-notebook"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"配置文件根目录d:\\软件项目\\学习项目\\HttpClientStudy\\Docs\\Publish\\HttpClientStudy.Core\n",
"{\"data\":\"操作成功\",\"code\":1,\"message\":\"成功\"}\n"
]
}
],
"source": [
"// 本机服务类\n",
"// 百度服务类\n",
"public sealed class LocalService \n",
"{\n",
" private readonly HttpClient _httpClient;\n",
" public LocalService()\n",
" {\n",
" //初始化httpClient\n",
" var baseHander = new SocketsHttpHandler() \n",
" { \n",
" MaxConnectionsPerServer = 1000 \n",
" };\n",
"\n",
" _httpClient = new HttpClient(baseHander)\n",
" {\n",
" Timeout = TimeSpan.FromSeconds(10),\n",
" BaseAddress = new Uri(WebApiConfigManager.GetWebApiConfig().BaseUrl),\n",
" };\n",
" }\n",
"\n",
" ///// <summary>\n",
" /// 获取百度首页长度\n",
" /// </summary>\n",
" public async Task<string> GetIndexAsync(string url)\n",
" {\n",
" var response = await _httpClient.GetAsync(url);\n",
" response.EnsureSuccessStatusCode();\n",
" var result = await response.Content.ReadAsStringAsync();\n",
" return result;\n",
" }\n",
"}\n",
"//调用示例\n",
"{\n",
" var service2 = new LocalService();\n",
" var result = await service2.GetIndexAsync(\"/api/Simple/GetAccount\");\n",
" Console.WriteLine(result);\n",
"}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 4、手动管理可复原(Polly)请求"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {
"vscode": {
"languageId": "polyglot-notebook"
}
},
"outputs": [
{
"data": {
"text/html": [
"<div><div></div><div></div><div><strong>Installed Packages</strong><ul><li><span>Microsoft.Extensions.Http.Polly, 8.0.7</span></li><li><span>Polly, 8.4.1</span></li></ul></div></div>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"配置文件根目录d:\\软件项目\\学习项目\\HttpClientStudy\\Docs\\Publish\\HttpClientStudy.Core\n",
"内部重试\n",
"内部重试\n",
"内部重试\n",
"Response status code does not indicate success: 500 (Internal Server Error).\n"
]
}
],
"source": [
"#r \"nuget:Polly\"\n",
"#r \"nuget:Microsoft.Extensions.Http.Polly\"\n",
"\n",
"using Polly;\n",
"using Polly.Simmy;\n",
"using Polly.Retry;\n",
"using Polly.Extensions;\n",
"\n",
"var pipleLine = new ResiliencePipelineBuilder()\n",
" .AddRetry(new RetryStrategyOptions()\n",
" {\n",
" ShouldHandle = new PredicateBuilder().Handle<Exception>(),\n",
" MaxRetryAttempts = 3, // Retry up to 3 times\n",
" OnRetry = args =>\n",
" {\n",
" // Due to how we have defined ShouldHandle, this delegate is called only if an exception occurred.\n",
" // Note the ! sign (null-forgiving operator) at the end of the command.\n",
" var exception = args.Outcome.Exception!; // The Exception property is nullable\n",
" Console.WriteLine(\"内部重试\");\n",
" return default;\n",
" }\n",
" })\n",
" .Build();\n",
"\n",
"var BaseUrl = WebApiConfigManager.GetWebApiConfig().BaseUrl;\n",
"HttpClient client = new HttpClient(new SocketsHttpHandler()\n",
"{\n",
" \n",
"})\n",
"{\n",
" BaseAddress = new Uri(BaseUrl),\n",
"};\n",
"\n",
"try\n",
"{\n",
" await pipleLine.ExecuteAsync(async (inneerToken)=>\n",
" {\n",
" var response = await client.GetAsync(\"api/Polly8/Retry_Exception\",inneerToken);\n",
" response.EnsureSuccessStatusCode();\n",
" });\n",
"}\n",
"catch(Exception ex)\n",
"{\n",
" Console.WriteLine(ex.Message);\n",
"}\n",
"finally\n",
"{\n",
"\n",
"}"
]
},
{
"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
}