From 0772a46d79538f46fd292d096fdc04e9e26695d6 Mon Sep 17 00:00:00 2001 From: bicijinlian Date: Wed, 7 Aug 2024 20:43:44 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Docs/1.3.0.基础使用.管理客户端.ipynb | 283 +++++++++++++----- .../Controllers/HelloController .cs | 63 ++++ 2 files changed, 278 insertions(+), 68 deletions(-) create mode 100644 HttpClientStudy.WebApp/Controllers/HelloController .cs diff --git a/Docs/1.3.0.基础使用.管理客户端.ipynb b/Docs/1.3.0.基础使用.管理客户端.ipynb index 2732b8c..c2694db 100644 --- a/Docs/1.3.0.基础使用.管理客户端.ipynb +++ b/Docs/1.3.0.基础使用.管理客户端.ipynb @@ -32,7 +32,7 @@ }, { "cell_type": "code", - "execution_count": 67, + "execution_count": 5, "metadata": { "dotnet_interactive": { "language": "csharp" @@ -48,7 +48,7 @@ { "data": { "text/html": [ - "
Installed Packages
  • Microsoft.Extensions.DependencyInjection, 8.0.0
  • Microsoft.Extensions.Http, 8.0.0
  • Microsoft.Extensions.Http.Polly, 8.0.7
  • Polly, 8.4.1
  • System.Net.Http.Json, 8.0.0
" + "
Installed Packages
  • Microsoft.Extensions.DependencyInjection, 8.0.0
  • Microsoft.Extensions.Http, 8.0.0
  • Microsoft.Extensions.Http.Polly, 8.0.7
  • Polly, 8.4.1
  • Refit, 7.1.2
  • Refit.HttpClientFactory, 7.1.2
  • System.Net.Http.Json, 8.0.0
" ] }, "metadata": {}, @@ -58,23 +58,9 @@ "name": "stdout", "output_type": "stream", "text": [ - "启动WebApi项目\r\n" - ] - }, - { - "data": { - "text/plain": [ - "e:\\王高峰\\我的项目\\学习项目\\HttpClientStudy\\Docs\\Publish\\HttpClientStudy.WebApp\\HttpClientStudy.WebApp.exe" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "程序[e:\\王高峰\\我的项目\\学习项目\\HttpClientStudy\\Docs\\Publish\\HttpClientStudy.WebApp\\HttpClientStudy.WebApp.exe]已在新的命令行窗口执行。如果未出现新命令行窗口,可能是程序错误造成窗口闪现!\r\n" + "配置文件根目录:e:\\王高峰\\我的项目\\学习项目\\HttpClientStudy\\Docs\\Publish\\HttpClientStudy.Core\n", + "启动WebApi项目\n", + "程序[e:\\王高峰\\我的项目\\学习项目\\HttpClientStudy\\Docs\\Publish\\HttpClientStudy.WebApp\\HttpClientStudy.WebApp.exe]已在新的命令行窗口执行。如果未出现新命令行窗口,可能是程序错误造成窗口闪现!\n" ] } ], @@ -85,6 +71,8 @@ "#r \"nuget:Microsoft.Extensions.DependencyInjection\"\n", "#r \"nuget:Polly\"\n", "#r \"nuget:Microsoft.Extensions.Http.Polly\"\n", + "#r \"nuget:Refit\" \n", + "#r \"nuget:Refit.HttpClientFactory\"\n", "#r \"./Publish/HttpClientStudy.Core/HttpClientStudy.Core.dll\"\n", "\n", "global using System;\n", @@ -121,15 +109,21 @@ "global using Polly.Registry;\n", "global using Polly.Telemetry;\n", "\n", + "global using Refit;\n", + "//global using Refit.HttpClientFactory;\n", + "\n", "global using HttpClientStudy.Config;\n", "global using HttpClientStudy.Core;\n", "global using HttpClientStudy.Core.Utilities;\n", "\n", - "//启动已发布的WebApi项目\n", - "Console.WriteLine(\"启动WebApi项目\");\n", + "//全局变量\n", + "var webApiBaseUrl = WebApiConfigManager.GetWebApiConfig().BaseUrl;\n", "var workDir = Environment.CurrentDirectory;\n", "var fullPath = System.IO.Path.GetFullPath(\"./Publish/HttpClientStudy.WebApp/HttpClientStudy.WebApp.exe\", workDir);\n", - "fullPath.Display();\n", + "//fullPath.Display();\n", + "\n", + "//启动已发布的WebApi项目\n", + "Console.WriteLine(\"启动WebApi项目\");\n", "var startMessage = AppUtility.RunWebApiExeFile(fullPath);\n", "Console.WriteLine(startMessage);\n" ] @@ -690,23 +684,19 @@ }, { "cell_type": "code", - "execution_count": 36, + "execution_count": null, "metadata": { + "dotnet_interactive": { + "language": "csharp" + }, + "polyglot_notebook": { + "kernelName": "csharp" + }, "vscode": { "languageId": "polyglot-notebook" } }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "9193\n", - "9193\n", - "18\n" - ] - } - ], + "outputs": [], "source": [ "/*\n", " 注意:\n", @@ -770,22 +760,19 @@ }, { "cell_type": "code", - "execution_count": 55, + "execution_count": null, "metadata": { + "dotnet_interactive": { + "language": "csharp" + }, + "polyglot_notebook": { + "kernelName": "csharp" + }, "vscode": { "languageId": "polyglot-notebook" } }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "A: 9508\n", - "A: 18\n" - ] - } - ], + "outputs": [], "source": [ "// IoC 多个HttpClient服务类\n", "\n", @@ -870,49 +857,209 @@ }, { "cell_type": "code", - "execution_count": 68, + "execution_count": null, "metadata": { + "dotnet_interactive": { + "language": "csharp" + }, + "polyglot_notebook": { + "kernelName": "csharp" + }, "vscode": { "languageId": "polyglot-notebook" } }, - "outputs": [ - { - "ename": "Error", - "evalue": "System.InvalidOperationException: An invalid request URI was provided. Either the request URI must be an absolute URI or BaseAddress must be set.\r\n at System.Net.Http.HttpClient.PrepareRequestMessage(HttpRequestMessage request)\r\n at System.Net.Http.HttpClient.GetAsync(String requestUri)\r\n at Submission#69.<>d__0.MoveNext()\r\n--- End of stack trace from previous location ---\r\n at Microsoft.CodeAnalysis.Scripting.ScriptExecutionState.RunSubmissionsAsync[TResult](ImmutableArray`1 precedingExecutors, Func`2 currentExecutor, StrongBox`1 exceptionHolderOpt, Func`2 catchExceptionOpt, CancellationToken cancellationToken)", - "output_type": "error", - "traceback": [ - "System.InvalidOperationException: An invalid request URI was provided. Either the request URI must be an absolute URI or BaseAddress must be set.\r\n", - " at System.Net.Http.HttpClient.PrepareRequestMessage(HttpRequestMessage request)\r\n", - " at System.Net.Http.HttpClient.GetAsync(String requestUri)\r\n", - " at Submission#69.<>d__0.MoveNext()\r\n", - "--- End of stack trace from previous location ---\r\n", - " at Microsoft.CodeAnalysis.Scripting.ScriptExecutionState.RunSubmissionsAsync[TResult](ImmutableArray`1 precedingExecutors, Func`2 currentExecutor, StrongBox`1 exceptionHolderOpt, Func`2 catchExceptionOpt, CancellationToken cancellationToken)" - ] - } - ], + "outputs": [], "source": [ - "//基础使用\n", + "//所有HttpClient配置\n", "{\n", " var services = new ServiceCollection();\n", - " services.AddHttpClient((provider, client) => \n", + " //添加一个委托,用于配置所有HttpClient实例。只执行一次。\n", + " services.ConfigureHttpClientDefaults(builder => \n", " {\n", - " client.BaseAddress = new Uri(\"https://www.baidu.com\");\n", + " //builder.UseSocketsHttpHandler();\n", + " //builder.SetHandlerLifetime(TimeSpan.FromMinutes(5));\n", + " \n", + " builder.ConfigureHttpClient(hc =>\n", + " {\n", + " hc.BaseAddress = new Uri(webApiBaseUrl);\n", + " });\n", " });\n", "\n", + " var factory = services.BuildServiceProvider().GetRequiredService();\n", + "\n", + " var client = factory.CreateClient();\n", + " var response = await client.GetAsync(\"/api/hello/ping\");\n", + " var data = await response.Content.ReadAsStringAsync();\n", + " Console.WriteLine(data);\n", + "}\n", + "\n", + "/*\n", + " 默认 HttpClient\n", + " 1、配置默认HttpClient时,AddHttpClient(Action)的Action不会被执行,ConfigureHttpClient()也不执行。原因暂时不明\n", + " 2、想配置默认HttpClient,可以使用ConfigureHttpClientDefaults方法,但此方法针对所有HttpClient实例(包括命名HttpClient)\n", + "*/\n", + "{\n", + " var services = new ServiceCollection();\n", + "\n", + " //默认HttpClient\n", + " services.AddHttpClient();\n", + "\n", + " //这种形式,不生效\n", + " // services.AddHttpClient((provider, client) => \n", + " // {\n", + " // client.BaseAddress = new Uri(webApiBaseUrl);\n", + " // });\n", + "\n", + " //这种形式,ConfigureHttpClient 也不生效\n", + " // services.AddHttpClient()\n", + " // .ConfigureHttpClient(config=>\n", + " // {\n", + " // config.BaseAddress = new Uri(webApiBaseUrl);\n", + " // });\n", + "\n", " var provider = services.BuildServiceProvider();\n", "\n", " var factory = provider.GetRequiredService();\n", "\n", - " var sum = factory.CreateClient().GetAsync(\"/\").Result.Content.ReadAsStringAsync().Result.Length;\n", + " var response = await factory.CreateClient().GetAsync(webApiBaseUrl+\"/api/hello/index\");\n", + " var content = await response.Content.ReadAsStringAsync();\n", " \n", - " Console.WriteLine(sum);\n", + " Console.WriteLine(content);\n", "}\n", "\n", - "//\n", + "//命名 HttpClient\n", "{\n", + " var clientA =\"httpClientA\";\n", + " var clientB =\"httpClientB\";\n", "\n", - "}" + " var services = new ServiceCollection();\n", + " services.AddHttpClient(clientA, (provider, client) => \n", + " {\n", + " client.BaseAddress = new Uri(webApiBaseUrl);\n", + " });\n", + " services.AddHttpClient(clientB, (provider, client) => \n", + " {\n", + " client.DefaultVersionPolicy = HttpVersionPolicy.RequestVersionOrHigher;\n", + " client.BaseAddress = new Uri(webApiBaseUrl);\n", + " })\n", + " .ConfigureHttpClient(client=>\n", + " {\n", + " client.Timeout = TimeSpan.FromSeconds(1);\n", + " client.DefaultRequestVersion = new Version(1, 1);\n", + " });\n", + "\n", + " var factory = services.BuildServiceProvider().GetRequiredService();\n", + "\n", + " var responseA = await factory.CreateClient(clientA).GetAsync(\"/api/hello/ping\");\n", + " var contentA = await responseA.Content.ReadAsStringAsync();\n", + " Console.WriteLine(contentA);\n", + "\n", + " var responseB = await factory.CreateClient(clientB).PostAsync(\"/api/hello/post\",null);\n", + " var contentB = await responseB.Content.ReadAsStringAsync();\n", + " Console.WriteLine(contentB);\n", + "}\n", + "\n", + "// 类型化客户端 HttpClient\n", + "public class HttpClientServiceA\n", + "{\n", + " public HttpClient Client { get; }\n", + " public HttpClientServiceA(HttpClient client)\n", + " {\n", + " Client = client;\n", + " Console.WriteLine(\"HttpClientServiceA => 构造函数执行一次\");\n", + " }\n", + "\n", + " public async Task GetIndexAsync()\n", + " {\n", + " var response = await Client.GetAsync(\"/api/hello/index\");\n", + " var content = await response.Content.ReadAsStringAsync();\n", + " return content;\n", + " }\n", + "}\n", + "\n", + "public class HttpClientServiceB\n", + "{\n", + " public HttpClient Client { get; }\n", + " public HttpClientServiceB(HttpClient client)\n", + " {\n", + " Client = client;\n", + " Console.WriteLine(\"HttpClientServiceB => 构造函数执行一次\");\n", + " }\n", + "\n", + " public async Task PingAsync()\n", + " {\n", + " var response = await Client.GetAsync(\"/api/hello/Ping\");\n", + " var content = await response.Content.ReadAsStringAsync();\n", + " return content;\n", + " }\n", + "}\n", + "\n", + "{\n", + " var services = new ServiceCollection();\n", + " services.AddHttpClient(client => \n", + " {\n", + " client.BaseAddress = new Uri(webApiBaseUrl);\n", + " Console.WriteLine(\"HttpClientServiceA => AddHttpClient 执行一次\");\n", + " })\n", + " .ConfigureHttpClient(client=>\n", + " {\n", + " client.Timeout = TimeSpan.FromSeconds(1);\n", + " Console.WriteLine(\"HttpClientServiceA => ConfigureHttpClient 执行一次\");\n", + " });\n", + "\n", + " services.AddHttpClient(client => \n", + " {\n", + " client.BaseAddress = new Uri(webApiBaseUrl);\n", + " Console.WriteLine(\"HttpClientServiceB => AddHttpClient 执行一次\");\n", + " })\n", + " .ConfigureHttpClient(client=>\n", + " {\n", + " client.Timeout = TimeSpan.FromSeconds(2);\n", + " Console.WriteLine(\"HttpClientServiceB => ConfigureHttpClient 执行一次\");\n", + " });\n", + "\n", + " var builder = services.BuildServiceProvider();\n", + "\n", + " var serviceA = builder.GetRequiredService();\n", + " var serviceB = builder.GetRequiredService();\n", + " //每获取一次类型化客户端,都会执行一交。\n", + " var serviceB2 = builder.GetRequiredService();\n", + "\n", + " var dataA = await serviceA.GetIndexAsync();\n", + " Console.WriteLine(dataA);\n", + "\n", + " var dataB = await serviceB.PingAsync();\n", + " Console.WriteLine(dataB);\n", + "\n", + " var dataB2 = await serviceB2.PingAsync();\n", + " Console.WriteLine(dataB2);\n", + "}\n", + "\n", + "// 类型化客户端2\n", + "{\n", + " var services = new ServiceCollection();\n", + " services.AddHttpClient(client => \n", + " {\n", + " client.BaseAddress = new Uri(webApiBaseUrl);\n", + " Console.WriteLine(\"HttpClientServiceA => AddHttpClient 执行一次\");\n", + " })\n", + " .AddTypedClient()\n", + " .ConfigureHttpClient(client=>\n", + " {\n", + " client.Timeout = TimeSpan.FromSeconds(1);\n", + " Console.WriteLine(\"HttpClientServiceA => ConfigureHttpClient 执行一次\");\n", + " });\n", + "}\n", + "\n", + "//todo: 生成式 HttpClient: Refit库\n", + "\n", + "/*\n", + " IFactoryHttpClient + Polly8\n", + " 1、引用库 Polly 和 Microsoft.Extensions.Http.Polly\n", + "*/\n", + "\n", + "\n" ] }, { diff --git a/HttpClientStudy.WebApp/Controllers/HelloController .cs b/HttpClientStudy.WebApp/Controllers/HelloController .cs new file mode 100644 index 0000000..594e0b3 --- /dev/null +++ b/HttpClientStudy.WebApp/Controllers/HelloController .cs @@ -0,0 +1,63 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; + +namespace HttpClientStudy.WebApp.Controllers +{ + /// + /// 简单接口 控制器 + /// + [Route("api/[controller]/[action]")] + [ApiController] + public class HelloController : ControllerBase + { + private ILogger _logger; + + /// + /// 构造 + /// + public HelloController (ILogger logger) + { + _logger = logger; + } + + /// + /// Ping + /// + /// Pong + [HttpGet] + public IActionResult Ping() + { + return Ok("Pong"); + } + + /// + /// Index + /// + /// + [HttpGet] + public IActionResult Index() + { + return Ok("Index"); + } + + /// + /// Get请求 + /// + /// + [HttpGet] + public IActionResult Get() + { + return Ok("Hello, world!"); + } + + /// + /// Post 请求 + /// + /// + [HttpPost] + public IActionResult Post() + { + return Ok("Hello, world!"); + } + } +}