diff --git a/.gitignore b/.gitignore index 0435efe..889b93c 100644 --- a/.gitignore +++ b/.gitignore @@ -436,6 +436,8 @@ FodyWeavers.xsd !.vscode/extensions.json !.vscode/*.code-snippets +Docs/.vscode/* + # Local History for Visual Studio Code .history/ diff --git a/Docs/1.0项目管理.dib b/Docs/1.0项目管理.dib index c9dab4c..09f768f 100644 --- a/Docs/1.0项目管理.dib +++ b/Docs/1.0项目管理.dib @@ -22,7 +22,7 @@ dotnet build ..\HttpClientStudy.sln #!pwsh # 可以发布整个项目,但要发布到默认目录下 -dotnet publish ..\HttpClientStudy.sln +# dotnet publish ..\HttpClientStudy.sln # 分项目发布到Docs目录下 dotnet publish ..\HttpClientStudy.Config\HttpClientStudy.Config.csproj -c Release -o .\Publish\HttpClientStudy.Config @@ -63,3 +63,67 @@ else { $WebAppProc.Kill(); Write-Host "$WebAppProcName 进程已退出" } + +#!markdown + +## 查看应用各种路径 + +#!csharp + +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using System.Diagnostics; +using System.Reflection; +using Microsoft.Extensions.DependencyInjection; + + var pathDic = new Dictionary() + { + //当前运行的exe的完整路径,包含exe文件名,只用于WinForm + {"Application.ExecutablePath",("程序集基完整路径(仅WinForm)", "Application.ExecutablePath 只适用于WinForm") }, + + //程序的启动路径:只用于WinForm + {"Application.StartupPath",("程序集启动路径(仅WinForm)", "Application.StartupPath 只适用于WinForm") }, + + //当前执行的exe或启动项目的路径,通过AppContext + {"AppContext.BaseDirectory",("执行或启动路径", AppContext.BaseDirectory) }, + + //当前执行的exe的目录,不包含exe名,使用AppDomain + {"AppDomain.CurrentDomain.BaseDirectory",("程序集解析程序用于探测程序集的基目录", AppDomain.CurrentDomain.BaseDirectory) }, + + //程序安装或启动基目录 包含应用程序的目录的名称 + {"AppDomain.CurrentDomain.SetupInformation.ApplicationBase",("程序安装或启动基目录", AppDomain.CurrentDomain.SetupInformation.ApplicationBase) }, + + //当前进程的主模块路径,包含exe名 + {"Process.GetCurrentProcess().MainModule.FileName",("当前进程的主模块路径", Process.GetCurrentProcess()?.MainModule?.FileName) }, + + //环境变量:用户当前工作目录的完整限定路径 + {"Environment.CurrentDirectory",("用户当前工作目录的完整限定路径", Environment.CurrentDirectory) }, + + //环境变量:当前exe的完整路径,包含exe名,通过命令行参数 + {"Environment.GetCommandLineArgs()[0]",("当前exe的完整路径", Environment.GetCommandLineArgs()[0]) }, + + //当前工作目录的路径(可变) + {"Directory.GetCurrentDirectory",("当前工作目录的路径(可变)", Directory.GetCurrentDirectory()) }, + + //当前Assembly的加载路径,包含dll或exe名 + {"Assembly.GetExecutingAssembly().Location",("当前Assembly的加载路径", Assembly.GetExecutingAssembly().Location) }, + + //入口程序集的路径 + {"Assembly.GetEntryAssembly().Location",("入口程序集的路径", Assembly.GetEntryAssembly()?.Location) }, + + //已过时:当前程序集的CodeBase路径,可能为file URI格式 + {"Assembly.GetExecutingAssembly().CodeBase",("当前程序集的CodeBase路径", Assembly.GetExecutingAssembly()?.CodeBase) }, + + //已过时:入口程序集的CodeBase路径,可能为file URI格式 + {"Assembly.GetEntryAssembly().CodeBase",("入口程序集的CodeBase路径", Assembly.GetEntryAssembly()?.CodeBase) }, + }; + + var message = string.Empty; + foreach (var item in pathDic) + { + message += $"{item.Key} => {item.Value.path}{Environment.NewLine}"; + } + + Console.WriteLine(message); diff --git a/Docs/1.2.使用准则.ipynb b/Docs/1.2.使用准则.ipynb index afb5785..a0a6b58 100644 --- a/Docs/1.2.使用准则.ipynb +++ b/Docs/1.2.使用准则.ipynb @@ -24,6 +24,59 @@ "## 0、准备工作:先执行下面单元,以启动WebApi及设置全局对象、方法及其它" ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "vscode": { + "languageId": "polyglot-notebook" + } + }, + "outputs": [], + "source": [ + "//全局设置\n", + "#r \"./Publish/HttpClientStudy.Core/HttpClientStudy.Core.dll\"\n", + "global using System.Net;\n", + "global using System.Net.Http;\n", + "global using System.Diagnostics;\n", + "global using System.Collections;\n", + "global using System.Text;\n", + "global using System.Linq;\n", + "global using System.IO;\n", + "\n", + "global using HttpClientStudy.Core;\n", + "\n", + "var global_queryDomain=\"soft.pwidc.cn\";\n", + "var global_queryPort=80;\n", + "var global_queryBaseUrl = $\"http://{global_queryDomain}:{global_queryPort}\";\n", + "\n", + "var global_ips =Dns.GetHostAddresses(global_queryDomani);\n", + "var global_queryIp = ips.First().ToString();\n", + "var global_netstat_filter = $\"{queryIp}:{global_queryPort}\";" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "统一使用示例" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "vscode": { + "languageId": "polyglot-notebook" + } + }, + "outputs": [], + "source": [ + "{ //大括号: 1、作用域隔离 2、方便整体代码折叠\n", + " Console.WriteLine(global_queryDomain);\n", + "}" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -33,7 +86,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": null, "metadata": { "dotnet_interactive": { "language": "pwsh" @@ -48,7 +101,7 @@ "outputs": [], "source": [ "#启动已发布的WebApi项目\n", - "Start-Process -FilePath \"dotnet.exe\" -ArgumentList \"Publish/HttpClientStudy.WebApi/HttpClientStudy.WebApi.dll\"" + "Start-Process -FilePath dotnet -ArgumentList \".\\Publish\\HttpClientStudy.WebApp\\HttpClientStudy.WebApp.dll\"" ] }, { @@ -253,40 +306,31 @@ }, "outputs": [], "source": [ - "using System.Net;\n", - "using System.Net.Http;\n", - "\n", - "//注意:不能使用百度 hao123等站点,可能是大厂服务器的设置问题,会导致查不到效果\n", - "var ips = await Dns.GetHostAddressesAsync(\"soft.pwidc.cn\");\n", - "string firstIp = ips.FirstOrDefault().ToString();\n", - "\t\n", - "foreach (var ipAddress in ips)\n", - "{\n", - " Console.WriteLine(ipAddress.MapToIPv4().ToString());\n", - "}\n", - "\n", - "//自定义行为\n", - "var socketsHandler = new SocketsHttpHandler\n", + "//测试连接寿命\n", "{\n", - " //连接池生命周期为10分钟:连接在池中保持活动时间为10分钟\n", - " PooledConnectionLifetime = TimeSpan.FromMinutes(10),\n", + " //自定义行为\n", + " var socketsHandler = new SocketsHttpHandler\n", + " {\n", + " //连接池生命周期为10分钟:连接在池中保持活动时间为10分钟\n", + " PooledConnectionLifetime = TimeSpan.FromMinutes(10),\n", "\n", - " //池化链接的空闲超时时间为5分钟: 5分钟内连接不被重用,则被释放后销毁\n", - " PooledConnectionIdleTimeout = TimeSpan.FromMinutes(5),\n", - " \n", - " //每端点的最大连接数设置为10个\n", - " MaxConnectionsPerServer = 10\n", - "};\n", + " //池化链接的空闲超时时间为5分钟: 5分钟内连接不被重用,则被释放后销毁\n", + " PooledConnectionIdleTimeout = TimeSpan.FromMinutes(5),\n", + " \n", + " //每端点的最大连接数设置为10个\n", + " MaxConnectionsPerServer = 10\n", + " };\n", "\n", - "var client = new HttpClient(socketsHandler);\n", + " var client = new HttpClient(socketsHandler);\n", "\n", - "for (var i = 0; i < 5; i++)\n", - "{\n", - " _ = await client.GetAsync(\"https://soft.pwidc.cn\");\n", - " await Task.Delay(TimeSpan.FromSeconds(2));\n", - "}\n", + " for (var i = 0; i < 5; i++)\n", + " {\n", + " _ = await client.GetAsync(global_queryBaseUrl);\n", + " await Task.Delay(TimeSpan.FromSeconds(2));\n", + " }\n", "\n", - "Console.WriteLine(\"程序运行大约要10-20秒,请在程序退出后,执行下面命令行查看网络情况\");\n" + " Console.WriteLine(\"程序运行大约要10-20秒,请在程序退出后,执行下面命令行查看网络情况\");\n", + "}" ] }, { @@ -312,12 +356,13 @@ }, "outputs": [], "source": [ - "# 如果没有查询到相关网络状态信息,PowerShell不针对出错,但.Net Interactive 会异常:Command failed: SubmitCode: #!set --value @csharp:xxxx\n", - "#!set --value @csharp:firstIp --name queryIp\n", + "# 若查询不到,则异常\n", + "#!set --value @csharp:global_netstat_filter --name queryFilter\n", + "\n", "Write-Host \"请先执行上面的单元,再执行本单元\"\n", "Write-Host \"网络状态\"\n", "\n", - "netstat -ano | findstr $queryIp" + "netstat -ano | findstr $queryFilter" ] }, { @@ -344,59 +389,56 @@ }, "outputs": [], "source": [ - "using System.IO;\n", - "using System.Diagnostics;\n", - "using System.Net;\n", - "using System.Net.Http;\n", - "\n", - "var ips = await Dns.GetHostAddressesAsync(\"soft.pwidc.cn\");\n", - "string firstIp = ips.FirstOrDefault().ToString();\n", - "\t\n", - "foreach (var ipAddress in ips)\n", - "{\n", - " Console.WriteLine(ipAddress.MapToIPv4().ToString());\n", - "}\n", + "{ //\n", + " var ips = await Dns.GetHostAddressesAsync(global_queryDomain);\n", + " string firstIp = ips.FirstOrDefault().ToString();\n", + " \n", + " foreach (var ipAddress in ips)\n", + " {\n", + " Console.WriteLine(ipAddress.MapToIPv4().ToString());\n", + " }\n", "\n", - "//自定义行为\n", - "var socketsHandler2 = new SocketsHttpHandler\n", - "{\n", - " PooledConnectionLifetime = TimeSpan.FromSeconds(1),\n", - " PooledConnectionIdleTimeout = TimeSpan.FromSeconds(1),\n", - " MaxConnectionsPerServer = 1\n", - "};\n", + " //自定义行为\n", + " var socketsHandler2 = new SocketsHttpHandler\n", + " {\n", + " PooledConnectionLifetime = TimeSpan.FromSeconds(1),\n", + " PooledConnectionIdleTimeout = TimeSpan.FromSeconds(1),\n", + " MaxConnectionsPerServer = 1\n", + " };\n", "\n", - "var client2 = new HttpClient(socketsHandler2);\n", + " var client2 = new HttpClient(socketsHandler2);\n", "\n", - "for (var i = 0; i < 5; i++)\n", - "{\n", - " if(i>0)\n", + " for (var i = 0; i < 5; i++)\n", " {\n", - " await Task.Delay(TimeSpan.FromSeconds(2));\n", + " if(i>0)\n", + " {\n", + " await Task.Delay(TimeSpan.FromSeconds(2));\n", + " }\n", + " _ = await client2.GetAsync(global_queryBaseUrl);\n", " }\n", - " _ = await client2.GetAsync(\"http://soft.pwidc.cn\");\n", - "}\n", "\n", - "Console.WriteLine(\"程序运行大约要10-20,请在程序退出后,执行下面命令行查看网络情况\");\n", + " Console.WriteLine(\"程序运行大约要10-20,请在程序退出后,执行下面命令行查看网络情况\");\n", "\n", - "//调用命令行,显示查看网络情况\n", - "string command = $\"netstat -ano | findstr {firstIp}\";\n", - " \n", - "// 创建一个新的ProcessStartInfo对象\n", - "ProcessStartInfo startInfo = new ProcessStartInfo(\"cmd\", $\"/c {command}\")\n", - "{\n", - " RedirectStandardOutput = true, // 重定向标准输出\n", - " UseShellExecute = false, // 不使用系统外壳程序启动\n", - " CreateNoWindow = true // 不创建新窗口\n", - "};\n", - " \n", - "// 启动进程\n", - "using (Process process = Process.Start(startInfo))\n", - "{\n", - " // 读取cmd的输出\n", - " using (StreamReader reader = process.StandardOutput)\n", + " //调用命令行,显示查看网络情况\n", + " string command = $\"netstat -ano | findstr {firstIp}\";\n", + " \n", + " // 创建一个新的ProcessStartInfo对象\n", + " ProcessStartInfo startInfo = new ProcessStartInfo(\"cmd\", $\"/c {command}\")\n", + " {\n", + " RedirectStandardOutput = true, // 重定向标准输出\n", + " UseShellExecute = false, // 不使用系统外壳程序启动\n", + " CreateNoWindow = true // 不创建新窗口\n", + " };\n", + " \n", + " // 启动进程\n", + " using (Process process = Process.Start(startInfo))\n", " {\n", - " string stdoutLine = reader.ReadToEnd();\n", - " Console.WriteLine(stdoutLine);\n", + " // 读取cmd的输出\n", + " using (StreamReader reader = process.StandardOutput)\n", + " {\n", + " string stdoutLine = reader.ReadToEnd();\n", + " Console.WriteLine(stdoutLine);\n", + " }\n", " }\n", "}" ] @@ -417,8 +459,8 @@ }, "outputs": [], "source": [ - "#!set --value @csharp:firstIp --name queryIp\n", - "netstat -ano | findstr $queryIp" + "#!set --value @csharp:global_netstat_filter --name queryFilter\n", + "netstat -ano | findstr $queryFilter" ] }, { @@ -439,50 +481,114 @@ "cell_type": "code", "execution_count": null, "metadata": { + "dotnet_interactive": { + "language": "csharp" + }, + "polyglot_notebook": { + "kernelName": "csharp" + }, "vscode": { "languageId": "polyglot-notebook" } }, "outputs": [], "source": [ - "\n", - "using System.Net;\n", - "var ips = await Dns.GetHostAddressesAsync(\"www.google.com\");\n", - "\t\n", - "foreach (var ipAddress in ips)\n", - "{\n", - "\t Console.WriteLine(ipAddress.MapToIPv4().ToString());\n", - "}\n", - "\n", - "var socketsHandler = new SocketsHttpHandler\n", + "/*\n", + "\t功能:将MaxConnectionsPerServer限制为2。然后启动200个任务,每个任务都向同一端点发出HTTP请求。这些任务将同时运行。所有请求竞争所花费的时间将写入控制台。\n", + "\t\t 随即调用用netstat命令查看连接:则根据定义的限制,我们可以看到两个已建立的连接。\n", + "*/\n", "{\n", - "\tPooledConnectionLifetime = TimeSpan.FromSeconds(60),\n", - "\tPooledConnectionIdleTimeout = TimeSpan.FromMinutes(20),\n", - "\tMaxConnectionsPerServer = 2\n", - "};\n", + "\tConsole.WriteLine(\"开始请求网络...\");\n", + "\tvar socketsHandler = new SocketsHttpHandler\n", + "\t{\n", + "\t\tPooledConnectionLifetime = TimeSpan.FromSeconds(60),\n", + "\t\tPooledConnectionIdleTimeout = TimeSpan.FromMinutes(20),\n", + "\t\tMaxConnectionsPerServer = 2\n", + "\t};\n", "\n", - "var client = new HttpClient(socketsHandler);\n", + "\tvar client = new HttpClient(socketsHandler);\n", "\n", - "var sw = Stopwatch.StartNew();\n", + "\tvar sw = Stopwatch.StartNew();\n", "\n", - "var tasks = Enumerable.Range(0, 200).Select(i => client.GetAsync(\"https://www.google.com\"));\n", + "\tvar tasks = Enumerable.Range(0, 200).Select(i => client.GetAsync(global_queryBaseUrl));\n", "\n", - "await Task.WhenAll(tasks);\n", + "\tawait Task.WhenAll(tasks);\n", "\n", - "sw.Stop();\n", - "\t\n", - "Console.WriteLine($\"{sw.ElapsedMilliseconds}ms taken for 200 requests\");\n", - "\t\n", - "//执行查看网络状态方法" + "\tsw.Stop();\n", + "\t\t\n", + "\tConsole.WriteLine($\"共请求了200次,耗时 {sw.ElapsedMilliseconds} 毫秒\");\n", + "\t\t\n", + "\t//执行查看网络状态方法\n", + "\tConsole.WriteLine(\"当前网络状态\");\n", + "\tvar message = CmdUtility.RunCmd($\"netstat -ano | findstr {global_netstat_filter}\");\n", + "\tConsole.WriteLine(message);\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "dotnet_interactive": { + "language": "pwsh" + }, + "polyglot_notebook": { + "kernelName": "pwsh" + }, + "vscode": { + "languageId": "polyglot-notebook" + } + }, + "outputs": [], + "source": [ + "# 重新查询当前网络状态\n", + "#!set --value @csharp:global_netstat_filter --name queryFilter\n", + "netstat -ano | findstr $queryFilter" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "该代码将MaxConnectionsPerServer限制为2。然后启动200个任务,每个任务都向同一端点发出HTTP请求。这些任务将同时运行。所有请求竞争所花费的时间将写入控制台。\n", - "如果使用netstat查看连接,则根据定义的限制,我们可以看到两个已建立的连接。\n", - "已建立\n" + "如果我们调整此代码以允许MaxConnectionsPerServer = 10,则可以重新运行该应用程序。耗时将减少大约4倍。" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "vscode": { + "languageId": "polyglot-notebook" + } + }, + "outputs": [], + "source": [ + "{ //MaxConnectionsPerServer 设置为10:网络连接将增加到10个,耗时将减少到1/4\n", + "\tConsole.WriteLine(\"开始请求网络...\");\n", + "\tvar socketsHandler = new SocketsHttpHandler\n", + "\t{\n", + "\t\tPooledConnectionLifetime = TimeSpan.FromSeconds(60),\n", + "\t\tPooledConnectionIdleTimeout = TimeSpan.FromMinutes(20),\n", + "\t\tMaxConnectionsPerServer = 10\n", + "\t};\n", + "\n", + "\tvar client = new HttpClient(socketsHandler);\n", + "\n", + "\tvar sw = Stopwatch.StartNew();\n", + "\n", + "\tvar tasks = Enumerable.Range(0, 200).Select(i => client.GetAsync(global_queryBaseUrl));\n", + "\n", + "\tawait Task.WhenAll(tasks);\n", + "\n", + "\tsw.Stop();\n", + "\t\t\n", + "\tConsole.WriteLine($\"共请求了200次,耗时 {sw.ElapsedMilliseconds} 毫秒\");\n", + "\t\t\n", + "\t//执行查看网络状态方法\n", + "\tConsole.WriteLine(\"当前网络状态\");\n", + "\tvar message = CmdUtility.RunCmd($\"netstat -ano | findstr {global_netstat_filter}\");\n", + "\tConsole.WriteLine(message);\n", + "}" ] }, { diff --git a/Docs/1.6.测试.ipynb b/Docs/1.6.测试.ipynb index 279e675..ac297bb 100644 --- a/Docs/1.6.测试.ipynb +++ b/Docs/1.6.测试.ipynb @@ -80,7 +80,7 @@ "outputs": [], "source": [ "#启动已发布的WebApi项目\n", - "Start-Process -FilePath \"Publish\\HttpClientStudy.WebApp\\HttpClientStudy.WebApp.exe\"" + "Start-Process -FilePath dotnet -ArgumentList \".\\Publish\\HttpClientStudy.WebApp\\HttpClientStudy.WebApp.dll\"" ] }, { @@ -131,31 +131,6 @@ " Write-Host \"$WebAppProcName 进程已退出\"\n", "}" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "dotnet_interactive": { - "language": "csharp" - }, - "polyglot_notebook": { - "kernelName": "csharp" - }, - "vscode": { - "languageId": "polyglot-notebook" - } - }, - "outputs": [], - "source": [ - "var basePath = System.Environment.CurrentDirectory;\n", - "\n", - "var filePath =\"./Docs/a.txt\";\n", - " \n", - "var full = System.IO.Path.GetFullPath(filePath,basePath);\n", - "\n", - "Console.WriteLine(full);" - ] } ], "metadata": { diff --git a/Docs/2.1.内核中的各种路径.ipynb b/Docs/2.1.内核中的各种路径.ipynb index 1a400df..b655651 100644 --- a/Docs/2.1.内核中的各种路径.ipynb +++ b/Docs/2.1.内核中的各种路径.ipynb @@ -23,7 +23,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "metadata": { "dotnet_interactive": { "language": "csharp" @@ -35,22 +35,7 @@ "languageId": "polyglot-notebook" } }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "应用程序的基准目录 [AppContext.BaseDirectory] : C:\\Users\\asus\\.nuget\\packages\\microsoft.dotnet-interactive\\1.0.522904\\tools\\net8.0\\any\\\n", - "程序安装当前基目录 [AppDomain.CurrentDomain.BaseDirectory] :C:\\Users\\asus\\.nuget\\packages\\microsoft.dotnet-interactive\\1.0.522904\\tools\\net8.0\\any\\\n", - "程序安装或启动基目录 [AppDomain.CurrentDomain.SetupInformation.ApplicationBase] :C:\\Users\\asus\\.nuget\\packages\\microsoft.dotnet-interactive\\1.0.522904\\tools\\net8.0\\any\\\n", - "进程主模块的完整路径 [Process.GetCurrentProcess().MainModule.FileName] :C:\\Program Files\\dotnet\\dotnet.exe\n", - "当前工作目录 [Environment.CurrentDirectory] :e:\\王高峰\\我的项目\\学习项目\\HttpClientStudy\\Docs\n", - "文件当前目录 [Directory.GetCurrentDirectory()] :e:\\王高峰\\我的项目\\学习项目\\HttpClientStudy\\Docs\n", - "可执行程序集目录 [Assembly.GetExecutingAssembly().Location] :\n", - "指定程序集目录 [Type.Assembly.Location] :C:\\Program Files\\dotnet\\shared\\Microsoft.NETCore.App\\8.0.5\\System.Private.CoreLib.dll\n" - ] - } - ], + "outputs": [], "source": [ "// C#中,内核执行时,各种默认路径如下:\n", "\n", @@ -62,31 +47,55 @@ "using System.Reflection;\n", "using Microsoft.Extensions.DependencyInjection;\n", "\n", - "//应用程序信息\n", + " var pathDic = new Dictionary() \n", + " {\n", + " //当前运行的exe的完整路径,包含exe文件名,只用于WinForm\n", + " {\"Application.ExecutablePath\",(\"程序集基完整路径(仅WinForm)\", \"Application.ExecutablePath 只适用于WinForm\") },\n", + "\n", + " //程序的启动路径:只用于WinForm\n", + " {\"Application.StartupPath\",(\"程序集启动路径(仅WinForm)\", \"Application.StartupPath 只适用于WinForm\") },\n", + "\n", + " //当前执行的exe或启动项目的路径,通过AppContext\n", + " {\"AppContext.BaseDirectory\",(\"执行或启动路径\",AppContext.BaseDirectory) }, \n", + "\n", + " //当前执行的exe的目录,不包含exe名,使用AppDomain\n", + " {\"AppDomain.CurrentDomain.BaseDirectory\",(\"程序集解析程序用于探测程序集的基目录\",AppDomain.CurrentDomain.BaseDirectory) }, \n", + "\n", + " //程序安装或启动基目录 包含应用程序的目录的名称\n", + " {\"AppDomain.CurrentDomain.SetupInformation.ApplicationBase\",(\"程序安装或启动基目录\",AppDomain.CurrentDomain.SetupInformation.ApplicationBase) }, \n", + "\n", + " //当前进程的主模块路径,包含exe名\n", + " {\"Process.GetCurrentProcess().MainModule.FileName\",(\"当前进程的主模块路径\",Process.GetCurrentProcess()?.MainModule?.FileName) }, \n", "\n", - "//程序的上下文基准目录:通常是应用程序启动时的目录,也可以理解为包含可执行文件的目录\n", - "Console.WriteLine($\"应用程序的基准目录 [AppContext.BaseDirectory] : {AppContext.BaseDirectory}\");\n", + " //环境变量:用户当前工作目录的完整限定路径\n", + " {\"Environment.CurrentDirectory\",(\"用户当前工作目录的完整限定路径\",Environment.CurrentDirectory) }, \n", "\n", - "//程序安装当前基目录 \n", - "Console.WriteLine($\"程序安装当前基目录 [AppDomain.CurrentDomain.BaseDirectory] :{AppDomain.CurrentDomain.BaseDirectory}\");\n", + " //环境变量:当前exe的完整路径,包含exe名,通过命令行参数\n", + " {\"Environment.GetCommandLineArgs()[0]\",(\"当前exe的完整路径\",Environment.GetCommandLineArgs()[0]) }, \n", "\n", - "//程序安装或启动基目录\n", - "Console.WriteLine($\"程序安装或启动基目录 [AppDomain.CurrentDomain.SetupInformation.ApplicationBase] :{AppDomain.CurrentDomain.SetupInformation.ApplicationBase}\");\n", + " //当前工作目录的路径(可变)\n", + " {\"Directory.GetCurrentDirectory\",(\"当前工作目录的路径(可变)\",Directory.GetCurrentDirectory()) },\n", + " \n", + " //当前Assembly的加载路径,包含dll或exe名\n", + " {\"Assembly.GetExecutingAssembly().Location\",(\"当前Assembly的加载路径\",Assembly.GetExecutingAssembly().Location) },\n", "\n", - "//进程主模块的完整路径\n", - "Console.WriteLine($\"进程主模块的完整路径 [Process.GetCurrentProcess().MainModule.FileName] :{Process.GetCurrentProcess()?.MainModule?.FileName}\");\n", + " //入口程序集的路径\n", + " {\"Assembly.GetEntryAssembly().Location\",(\"入口程序集的路径\",Assembly.GetEntryAssembly()?.Location) },\n", "\n", - "//环境变量:当前工作目录\n", - "Console.WriteLine($\"当前工作目录 [Environment.CurrentDirectory] :{Environment.CurrentDirectory}\");\n", + " //已过时:当前程序集的CodeBase路径,可能为file URI格式\n", + " {\"Assembly.GetExecutingAssembly().CodeBase\",(\"当前程序集的CodeBase路径\",Assembly.GetExecutingAssembly()?.CodeBase) },\n", "\n", - "//文件当前目录:当前工作目录:不一定是启动目录\n", - "Console.WriteLine($\"文件当前目录 [Directory.GetCurrentDirectory()] :{Directory.GetCurrentDirectory()}\");\n", + " //已过时:入口程序集的CodeBase路径,可能为file URI格式\n", + " {\"Assembly.GetEntryAssembly().CodeBase\",(\"入口程序集的CodeBase路径\",Assembly.GetEntryAssembly()?.CodeBase) },\n", + " };\n", "\n", - "//可执行程序集目录\n", - "Console.WriteLine($\"可执行程序集目录 [Assembly.GetExecutingAssembly().Location] :{Assembly.GetExecutingAssembly().Location}\");\n", + " var message = string.Empty;\n", + " foreach (var item in pathDic)\n", + " {\n", + " message += $\"{item.Key} => {item.Value.path}{Environment.NewLine}\";\n", + " }\n", "\n", - "//指定程序集目录:可以是引用类库、指定类所在类库目录 \n", - "Console.WriteLine($\"指定程序集目录 [Type.Assembly.Location] :{typeof(System.Environment).Assembly.Location}\");\n" + " Console.WriteLine(message);" ] } ], diff --git a/Docs/学习.ps1 b/Docs/学习.ps1 index a60976d..e6b023c 100644 --- a/Docs/学习.ps1 +++ b/Docs/学习.ps1 @@ -1,15 +1 @@ -Start-Process -FilePath "pwsh" -ArgumentList "-h" - -Pause - -# 关闭项目进程 -$WebAppProcName ="HttpClientStudy.WebApp"; -$WebAppProc = Get-Process $WebAppProcName -ErrorAction Ignore -if($null -eq $WebAppProc) -{ - Write-Host "进程没有找到,可能已经" -} -else { - $WebAppProc.Kill(); - Write-Host "$WebAppProcName 进程已退出" -} \ No newline at end of file +Start-Process -FilePath "dotnet.exe" -ArgumentList ".\Publish/HttpClientStudy.WebApi/HttpClientStudy.WebApi.dll" \ No newline at end of file diff --git a/HttpClientStudy.Config/WebApiConfigExtensions.cs b/HttpClientStudy.Config/WebApiConfigExtensions.cs index 1ed4244..f4853b8 100644 --- a/HttpClientStudy.Config/WebApiConfigExtensions.cs +++ b/HttpClientStudy.Config/WebApiConfigExtensions.cs @@ -32,38 +32,16 @@ namespace HttpClientStudy.Config /// public static IConfigurationBuilder AddWebApiConfiguration(this IConfigurationBuilder configuration) { - /* - //应用程序信息 - - //程序的上下文基准目录:通常是应用程序启动时的目录,也可以理解为包含可执行文件的目录 - Console.WriteLine($"应用程序的基准目录[AppContext.BaseDirectory] = {AppContext.BaseDirectory}"); - - //程序安装或启动基目录 - Console.WriteLine($"程序安装或启动基目录[AppDomain.CurrentDomain.SetupInformation.ApplicationBase]:{AppDomain.CurrentDomain.SetupInformation.ApplicationBase}"); - - //进程主模块的完整路径 - Console.WriteLine($"进程主模块的完整路径[Process.GetCurrentProcess().MainModule.FileName]:{Process.GetCurrentProcess()?.MainModule?.FileName}"); - - //环境变量:当前工作目录 - Console.WriteLine($"当前工作目录[Environment.CurrentDirectory]:{Environment.CurrentDirectory}"); - - //文件当前目录:当前工作目录:不一定是启动目录 - Console.WriteLine($"文件当前目录[Directory.GetCurrentDirectory()]:{Directory.GetCurrentDirectory()}"); - - //可执行程序集目录 - Console.WriteLine($"可执行程序集目录[Assembly.GetExecutingAssembly().Location]:{Assembly.GetExecutingAssembly().Location}"); - - //指定程序集目录:可以是引用类库、指定类所在类库目录 - Console.WriteLine($"指定程序集目录[Type.Assembly.Location]:{typeof(WebApiConfigExtensions).Assembly.Location}"); - */ - + //配置文件名称 + configuration.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true); + configuration.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}.json", optional: true, reloadOnChange: true); //配置文件根目录:配置项目Dll文件所在目录(被其它项目引用时,引用后dll的文件所在目录) string configDellPath = Path.GetDirectoryName(typeof(WebApiConfig).Assembly.Location) ?? Directory.GetCurrentDirectory(); configuration.SetBasePath(configDellPath); Console.WriteLine($"配置文件根目录:{configDellPath}"); configuration.AddJsonFile($"ConfigFiles/Config.json", optional: false, reloadOnChange: true); - configuration.AddJsonFile($"ConfigFiles/Config.{System.Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}.json", optional: true, reloadOnChange: true); + configuration.AddJsonFile($"ConfigFiles/Config.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}.json", optional: true, reloadOnChange: true); return configuration; } diff --git a/HttpClientStudy.Core/Utilities/AppUtility.cs b/HttpClientStudy.Core/Utilities/AppUtility.cs new file mode 100644 index 0000000..82c8ada --- /dev/null +++ b/HttpClientStudy.Core/Utilities/AppUtility.cs @@ -0,0 +1,68 @@ +using System; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Collections.Generic; +using System.Diagnostics; +using System.Reflection; + + +namespace HttpClientStudy.Core.Utilities +{ + /// + /// 应用工具类 + /// + public class AppUtility + { + /// + /// 获取应用运行时各种路径 + /// + /// + public static IDictionary GetApplicationPaths() + { + var pathDic = new Dictionary() + { + //当前运行的exe的完整路径,包含exe文件名,只用于WinForm + {"Application.ExecutablePath",("程序集基完整路径(仅WinForm)", "Application.ExecutablePath 只适用于WinForm") }, + + //程序的启动路径:只用于WinForm + {"Application.StartupPath",("程序集启动路径(仅WinForm)", "Application.StartupPath 只适用于WinForm") }, + + //当前执行的exe或启动项目的路径,通过AppContext + {"AppContext.BaseDirectory",("执行或启动路径",AppContext.BaseDirectory) }, + + //当前执行的exe的目录,不包含exe名,使用AppDomain + {"AppDomain.CurrentDomain.BaseDirectory",("程序集解析程序用于探测程序集的基目录",AppDomain.CurrentDomain.BaseDirectory) }, + + //程序安装或启动基目录 包含应用程序的目录的名称 + {"AppDomain.CurrentDomain.SetupInformation.ApplicationBase",("程序安装或启动基目录",AppDomain.CurrentDomain.SetupInformation.ApplicationBase) }, + + //当前进程的主模块路径,包含exe名 + {"Process.GetCurrentProcess().MainModule.FileName",("当前进程的主模块路径",Process.GetCurrentProcess()?.MainModule?.FileName) }, + + //环境变量:用户当前工作目录的完整限定路径 + {"Environment.CurrentDirectory",("用户当前工作目录的完整限定路径",Environment.CurrentDirectory) }, + + //环境变量:当前exe的完整路径,包含exe名,通过命令行参数 + {"Environment.GetCommandLineArgs()[0]",("当前exe的完整路径",Environment.GetCommandLineArgs()[0]) }, + + //当前工作目录的路径(可变) + {"Directory.GetCurrentDirectory",("当前工作目录的路径(可变)",Directory.GetCurrentDirectory()) }, + + //当前Assembly的加载路径,包含dll或exe名 + {"Assembly.GetExecutingAssembly().Location",("当前Assembly的加载路径",Assembly.GetExecutingAssembly().Location) }, + + //入口程序集的路径 + {"Assembly.GetEntryAssembly().Location",("入口程序集的路径",Assembly.GetEntryAssembly()?.Location) }, + + //已过时:当前程序集的CodeBase路径,可能为file URI格式 + {"Assembly.GetExecutingAssembly().CodeBase",("当前程序集的CodeBase路径",Assembly.GetExecutingAssembly()?.CodeBase) }, + + //已过时:入口程序集的CodeBase路径,可能为file URI格式 + {"Assembly.GetEntryAssembly().CodeBase",("入口程序集的CodeBase路径",Assembly.GetEntryAssembly()?.CodeBase) }, + }; + + return pathDic; + } + } +} diff --git a/HttpClientStudy.UnitTest/UtilitiesTest/AppUtilityTest.cs b/HttpClientStudy.UnitTest/UtilitiesTest/AppUtilityTest.cs new file mode 100644 index 0000000..ac78fb4 --- /dev/null +++ b/HttpClientStudy.UnitTest/UtilitiesTest/AppUtilityTest.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using HttpClientStudy.Core.Utilities; + +namespace HttpClientStudy.UnitTest.UtilitiesTest +{ + public class AppUtilityTest + { + private readonly ITestOutputHelper _output; + public AppUtilityTest(ITestOutputHelper testOutput) + { + _output = testOutput; + } + + [Fact] + public void Test() + { + var dic = AppUtility.GetApplicationPaths(); + + string message = string.Empty; + foreach (var path in dic) + { + message += ($"{path.Key} : {path.Value.path}{Environment.NewLine}"); + } + + _output.WriteLine(message); + } + } +} diff --git a/HttpClientStudy.WebApp/Program.cs b/HttpClientStudy.WebApp/Program.cs index 1768354..1aafb22 100644 --- a/HttpClientStudy.WebApp/Program.cs +++ b/HttpClientStudy.WebApp/Program.cs @@ -37,7 +37,17 @@ namespace HttpClientStudy.WebApp var builder = WebApplication.CreateBuilder(args); + #region ļ + var configBasePath = AppContext.BaseDirectory; + Console.WriteLine($"WebAppļĿ¼{configBasePath}"); + builder.Configuration.SetBasePath(configBasePath); + builder.Configuration.AddJsonFile("appsettings.json", false, true); + builder.Configuration.AddJsonFile($"appsettings.{builder.Environment.EnvironmentName}.json", true, true); + builder.Configuration.AddJsonFile($"configFiles/Config.json", false, true); + #endregion + #region ע + builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); diff --git a/HttpClientStudy.WebApp/Properties/launchSettings.json b/HttpClientStudy.WebApp/Properties/launchSettings.json index a664898..6047295 100644 --- a/HttpClientStudy.WebApp/Properties/launchSettings.json +++ b/HttpClientStudy.WebApp/Properties/launchSettings.json @@ -14,6 +14,7 @@ "dotnetRunMessages": true, "launchBrowser": true, "launchUrl": "swagger", + //被appsettings配置文件覆盖 "applicationUrl": "http://localhost:5189", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development"