|
|
@ -75,10 +75,8 @@
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"global using Microsoft.Extensions.DependencyInjection;\n",
|
|
|
|
"global using Microsoft.Extensions.DependencyInjection;\n",
|
|
|
|
"global using Microsoft.Extensions.DependencyInjection.Extensions;\n",
|
|
|
|
"global using Microsoft.Extensions.DependencyInjection.Extensions;\n",
|
|
|
|
"\n",
|
|
|
|
|
|
|
|
"global using Microsoft.Extensions.Logging;\n",
|
|
|
|
"global using Microsoft.Extensions.Logging;\n",
|
|
|
|
"global using Microsoft.Extensions.Logging.Console;\n",
|
|
|
|
"global using Microsoft.Extensions.Logging.Console;\n",
|
|
|
|
"\n",
|
|
|
|
|
|
|
|
"global using Microsoft.Extensions.Http.Logging;\n",
|
|
|
|
"global using Microsoft.Extensions.Http.Logging;\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
@ -1748,6 +1746,18 @@
|
|
|
|
"## 7 工厂 + Polly V8"
|
|
|
|
"## 7 工厂 + Polly V8"
|
|
|
|
]
|
|
|
|
]
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
"cell_type": "markdown",
|
|
|
|
|
|
|
|
"metadata": {},
|
|
|
|
|
|
|
|
"source": [
|
|
|
|
|
|
|
|
"IFactoryHttpClient 与 Polly配合,可轻松实现重试、熔断、降级、限流等功能,本文只是简略的给出常用的使用方法,详情会写在 Polly学习项目中。[Polly 官方参考](https://github.com/App-vNext/Polly/wiki/Polly-and-HttpClientFactory)\n",
|
|
|
|
|
|
|
|
"使用步骤:\n",
|
|
|
|
|
|
|
|
"1. 引用 Polly v8 和 Microsoft.Extensions.Http.Polly 包\n",
|
|
|
|
|
|
|
|
"2. 配置命名客户端\n",
|
|
|
|
|
|
|
|
"3. 使用 AddTransientHttpErrorPolicy 快捷方法,配置策略\n",
|
|
|
|
|
|
|
|
"4. 使用其它方式配置,并且可以使用多策略、注册策略、上下文等功能"
|
|
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
},
|
|
|
|
{
|
|
|
|
{
|
|
|
|
"cell_type": "markdown",
|
|
|
|
"cell_type": "markdown",
|
|
|
|
"metadata": {},
|
|
|
|
"metadata": {},
|
|
|
@ -1759,10 +1769,7 @@
|
|
|
|
"cell_type": "markdown",
|
|
|
|
"cell_type": "markdown",
|
|
|
|
"metadata": {},
|
|
|
|
"metadata": {},
|
|
|
|
"source": [
|
|
|
|
"source": [
|
|
|
|
"工厂可以和Polly(v8)一起使用:\n",
|
|
|
|
"使用快捷方法AddTransientHttpErrorPolicy,进行常用功能使用。"
|
|
|
|
"1. 引用 Polly v8 和 Microsoft.Extensions.Http.Polly 包\n",
|
|
|
|
|
|
|
|
"2. 配置命名客户端\n",
|
|
|
|
|
|
|
|
"3. 使用 AddTransientHttpErrorPolicy 配置策略"
|
|
|
|
|
|
|
|
]
|
|
|
|
]
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
{
|
|
|
@ -1781,31 +1788,33 @@
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"outputs": [],
|
|
|
|
"outputs": [],
|
|
|
|
"source": [
|
|
|
|
"source": [
|
|
|
|
"//便捷应用:AddTransientHttpErrorPolicy() 方法,添加常用瞬时错误重试策略\n",
|
|
|
|
"/*\n",
|
|
|
|
|
|
|
|
" 便捷应用:AddTransientHttpErrorPolicy() 方法,添加常用瞬时错误重试策略\n",
|
|
|
|
|
|
|
|
"*/\n",
|
|
|
|
"{\n",
|
|
|
|
"{\n",
|
|
|
|
" var services = new ServiceCollection();\n",
|
|
|
|
" var services = new ServiceCollection();\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
" services.AddHttpClient(\"ClientA\")\n",
|
|
|
|
" services.AddHttpClient(string.Empty)\n",
|
|
|
|
|
|
|
|
" //配置默认命名客户端\n",
|
|
|
|
" .ConfigureHttpClient(client => \n",
|
|
|
|
" .ConfigureHttpClient(client => \n",
|
|
|
|
" {\n",
|
|
|
|
" {\n",
|
|
|
|
" client.BaseAddress = new Uri(webApiBaseUrl);\n",
|
|
|
|
" client.BaseAddress = new Uri(webApiBaseUrl);\n",
|
|
|
|
" })\n",
|
|
|
|
" })\n",
|
|
|
|
|
|
|
|
" //设置Policy错误处理快捷扩展方法\n",
|
|
|
|
" .AddTransientHttpErrorPolicy(builder => builder.WaitAndRetryAsync\n",
|
|
|
|
" .AddTransientHttpErrorPolicy(builder => builder.WaitAndRetryAsync\n",
|
|
|
|
" (\n",
|
|
|
|
" (\n",
|
|
|
|
" new[]\n",
|
|
|
|
" new[]\n",
|
|
|
|
" {\n",
|
|
|
|
" {\n",
|
|
|
|
" TimeSpan.FromSeconds(1),\n",
|
|
|
|
" TimeSpan.FromSeconds(1),\n",
|
|
|
|
" TimeSpan.FromSeconds(2),\n",
|
|
|
|
" TimeSpan.FromSeconds(2),\n",
|
|
|
|
" TimeSpan.FromSeconds(4)\n",
|
|
|
|
" TimeSpan.FromSeconds(4),\n",
|
|
|
|
" }\n",
|
|
|
|
" }\n",
|
|
|
|
" ))\n",
|
|
|
|
" ))\n",
|
|
|
|
" .AddTransientHttpErrorPolicy(builder => builder.Fallback<string>());\n",
|
|
|
|
" //可以多次调用:设置多个策略\n",
|
|
|
|
|
|
|
|
" .AddTransientHttpErrorPolicy(builder => builder.RetryAsync(1));\n",
|
|
|
|
" \n",
|
|
|
|
" \n",
|
|
|
|
" var factory = services.BuildServiceProvider().GetService<IHttpClientFactory>();\n",
|
|
|
|
" var factory = services.BuildServiceProvider().GetService<IHttpClientFactory>();\n",
|
|
|
|
" var clientA = factory.CreateClient(\"ClientA\");\n",
|
|
|
|
" var content = await factory.CreateClient().GetStringAsync(\"/api/polly8/RandomException\");\n",
|
|
|
|
" var response = await clientA.GetAsync(\"/api/polly8/RandomException\");\n",
|
|
|
|
|
|
|
|
" response.EnsureSuccessStatusCode();\n",
|
|
|
|
|
|
|
|
" var content = await response.Content.ReadAsStringAsync();\n",
|
|
|
|
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
" Console.WriteLine($\"响应内容:{content}\");\n",
|
|
|
|
" Console.WriteLine($\"响应内容:{content}\");\n",
|
|
|
|
"}"
|
|
|
|
"}"
|
|
|
@ -1818,6 +1827,13 @@
|
|
|
|
"### 使用通过传统 Polly 语法配置的任何策略"
|
|
|
|
"### 使用通过传统 Polly 语法配置的任何策略"
|
|
|
|
]
|
|
|
|
]
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
"cell_type": "markdown",
|
|
|
|
|
|
|
|
"metadata": {},
|
|
|
|
|
|
|
|
"source": [
|
|
|
|
|
|
|
|
"使用 AddPolicyHandler 方法及其重载也可用于接受任何 IAsyncPolicy<HttpResponseMessage> ,因此可以定义和应用任何类型的策略:可以指定要处理的内容和处理方式。"
|
|
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
},
|
|
|
|
{
|
|
|
|
{
|
|
|
|
"cell_type": "code",
|
|
|
|
"cell_type": "code",
|
|
|
|
"execution_count": null,
|
|
|
|
"execution_count": null,
|
|
|
@ -1834,21 +1850,53 @@
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"outputs": [],
|
|
|
|
"outputs": [],
|
|
|
|
"source": [
|
|
|
|
"source": [
|
|
|
|
|
|
|
|
"/*\n",
|
|
|
|
|
|
|
|
" 传统方式配置Polly策略\n",
|
|
|
|
|
|
|
|
"*/\n",
|
|
|
|
|
|
|
|
"//创建策略\n",
|
|
|
|
"{\n",
|
|
|
|
"{\n",
|
|
|
|
|
|
|
|
" var services = new ServiceCollection();\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
" var policy = Policy.Handle<Exception>()\n",
|
|
|
|
" //重试策略\n",
|
|
|
|
" .WaitAndRetryAsync\n",
|
|
|
|
" var retryePolicy = Policy\n",
|
|
|
|
" (\n",
|
|
|
|
" .Handle<HttpRequestException>()\n",
|
|
|
|
" new[]\n",
|
|
|
|
" .OrResult<HttpResponseMessage>(response => \n",
|
|
|
|
" {\n",
|
|
|
|
" {\n",
|
|
|
|
" TimeSpan.FromSeconds(1),\n",
|
|
|
|
" return response.StatusCode == System.Net.HttpStatusCode.Created;\n",
|
|
|
|
" TimeSpan.FromSeconds(2),\n",
|
|
|
|
" })\n",
|
|
|
|
" TimeSpan.FromSeconds(4)\n",
|
|
|
|
" .WaitAndRetryAsync(new TimeSpan[]{TimeSpan.FromSeconds(1), TimeSpan.FromMilliseconds(2)});\n",
|
|
|
|
|
|
|
|
" //调用\n",
|
|
|
|
|
|
|
|
" services\n",
|
|
|
|
|
|
|
|
" .AddHttpClient(string.Empty)\n",
|
|
|
|
|
|
|
|
" .AddPolicyHandler(retryePolicy);\n",
|
|
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
|
|
" //超时策略\n",
|
|
|
|
|
|
|
|
" var timeoutPolicy = Policy.TimeoutAsync<HttpResponseMessage>(10);\n",
|
|
|
|
|
|
|
|
" services\n",
|
|
|
|
|
|
|
|
" .AddHttpClient(\"timeoutPolicy\")\n",
|
|
|
|
|
|
|
|
" .AddPolicyHandler(timeoutPolicy);\n",
|
|
|
|
|
|
|
|
" \n",
|
|
|
|
|
|
|
|
" /* 普通策略转换\n",
|
|
|
|
|
|
|
|
" 所有通过 HttpClient 的调用都返回 HttpResponseMessage 因此配置的策略必须是 IAsyncPolicy<HttpResponseMessage> \n",
|
|
|
|
|
|
|
|
" 通过简单、便捷的 AsAsyncPolicy<HttpResponseMessage>()方法,将非通用策略 IAsyncPolicy 转换为 IAsyncPolicy<HttpResponseMessage> \n",
|
|
|
|
|
|
|
|
" */\n",
|
|
|
|
|
|
|
|
" var timeoutPolicy2 = Policy.TimeoutAsync(2);\n",
|
|
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
|
|
" services\n",
|
|
|
|
|
|
|
|
" .AddHttpClient(\"timeoutPolicy2\")\n",
|
|
|
|
|
|
|
|
" //转换通用策略\n",
|
|
|
|
|
|
|
|
" .AddPolicyHandler(timeoutPolicy2.AsAsyncPolicy<HttpResponseMessage>());\n",
|
|
|
|
"}\n",
|
|
|
|
"}\n",
|
|
|
|
" );\n",
|
|
|
|
"\n",
|
|
|
|
|
|
|
|
"//示例\n",
|
|
|
|
|
|
|
|
"{\n",
|
|
|
|
|
|
|
|
" //创建策略\n",
|
|
|
|
|
|
|
|
" var policy = Policy.RateLimitAsync<HttpResponseMessage>(3,TimeSpan.FromSeconds(10));\n",
|
|
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
|
|
" //使用\n",
|
|
|
|
" var services = new ServiceCollection();\n",
|
|
|
|
" var services = new ServiceCollection();\n",
|
|
|
|
"\n",
|
|
|
|
"\n",
|
|
|
|
" services.AddHttpClient(\"ClientA\")\n",
|
|
|
|
" services.AddHttpClient(string.Empty)\n",
|
|
|
|
" .ConfigureHttpClient(client => \n",
|
|
|
|
" .ConfigureHttpClient(client => \n",
|
|
|
|
" {\n",
|
|
|
|
" {\n",
|
|
|
|
" client.BaseAddress = new Uri(webApiBaseUrl);\n",
|
|
|
|
" client.BaseAddress = new Uri(webApiBaseUrl);\n",
|
|
|
@ -1866,14 +1914,16 @@
|
|
|
|
" )\n",
|
|
|
|
" )\n",
|
|
|
|
" )\n",
|
|
|
|
" )\n",
|
|
|
|
" .AddPolicyHandler(policy);\n",
|
|
|
|
" .AddPolicyHandler(policy);\n",
|
|
|
|
" \n",
|
|
|
|
" try\n",
|
|
|
|
|
|
|
|
" {\n",
|
|
|
|
" var factory = services.BuildServiceProvider().GetService<IHttpClientFactory>();\n",
|
|
|
|
" var factory = services.BuildServiceProvider().GetService<IHttpClientFactory>();\n",
|
|
|
|
" var clientA = factory.CreateClient(\"ClientA\");\n",
|
|
|
|
" var content = await factory.CreateClient().GetStringAsync(\"/api/polly8/RandomException\");\n",
|
|
|
|
" var response = await clientA.GetAsync(\"/api/polly8/RandomException\");\n",
|
|
|
|
|
|
|
|
" response.EnsureSuccessStatusCode();\n",
|
|
|
|
|
|
|
|
" var content = await response.Content.ReadAsStringAsync();\n",
|
|
|
|
|
|
|
|
"\n",
|
|
|
|
|
|
|
|
" Console.WriteLine($\"响应内容:{content}\");\n",
|
|
|
|
" Console.WriteLine($\"响应内容:{content}\");\n",
|
|
|
|
|
|
|
|
" }\n",
|
|
|
|
|
|
|
|
" catch(Exception ex)\n",
|
|
|
|
|
|
|
|
" {\n",
|
|
|
|
|
|
|
|
" Console.WriteLine($\"未处理的异常:{ex.Message}\");\n",
|
|
|
|
|
|
|
|
" }\n",
|
|
|
|
"}"
|
|
|
|
"}"
|
|
|
|
]
|
|
|
|
]
|
|
|
|
},
|
|
|
|
},
|
|
|
@ -1891,6 +1941,13 @@
|
|
|
|
"### 动态选择策略"
|
|
|
|
"### 动态选择策略"
|
|
|
|
]
|
|
|
|
]
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
"cell_type": "markdown",
|
|
|
|
|
|
|
|
"metadata": {},
|
|
|
|
|
|
|
|
"source": [
|
|
|
|
|
|
|
|
"### 从注册表中选择策略"
|
|
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
},
|
|
|
|
{
|
|
|
|
{
|
|
|
|
"cell_type": "markdown",
|
|
|
|
"cell_type": "markdown",
|
|
|
|
"metadata": {},
|
|
|
|
"metadata": {},
|
|
|
|