Vscode和Rider配置Asp.NetCore 调试和发布项目

文章主要讲述了 Asp.NetCore 在 VsCode 和 Rider 中配置带参数调试和发布项目。

1. VsCode 中配置调试

1.1 launch.json 文件配置
launch.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

{
"version": "0.2.0",
"configurations": [
// 整个配置可以配置多个,启动时在 VsCode 的调试启动下拉列表中
{
// 调试配置的名称,会显示在 VsCode 的调试启动下拉列表中
"name": "asp.netcore -1 ",
// 指定调试器类型,coreclr 用于 .NET Core 应用程序
"type": "coreclr",
// 指定调试模式为"启动"(而非"附加"到已运行的进程)。
"request": "launch",
// 在开始调试前执行的任务,这里会执行名为 "build-xxx" 的构建任务(通常在 tasks.json 中定义)。
"preLaunchTask": "build-xxx",
// 指定要调试的程序路径:
// ${workspaceFolder}: VS Code 工作区根目录
// 指向 xxxProject 项目的 net8.0 调试版本的 DLL 文件
"program": "${workspaceFolder}/xxxProject/bin/Debug/net8.0/xxx.dll",
// 传递给应用程序的命令行参数:
// --devConfig xxxArg: 指定使用名为 "xxxArg" 的开发配置
"args": [
"--devConfig",
"xxxArg",
],
// 设置工作目录为 xxxProject 项目目录
"cwd": "${workspaceFolder}/xxxProject",
// 是否在程序入口点自动暂停,false 表示不暂停。
"stopAtEntry": false,
// 当检测到服务器就绪时的操作:
// action: "openExternally" 表示在外部浏览器中打开
// pattern: 用于从控制台输出中提取 URL 的正则表达式(匹配 "Now listening on:" 后的 URL)
"serverReadyAction": {
"action": "openExternally",
"pattern": "\\bNow listening on:\\s+(https?://\\S+)"
},
// 设置环境变量:
// ASPNETCORE_ENVIRONMENT: 设置为 "Development",表示这是开发环境
"env": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
// 映射编译路径到源文件路径:
// 将运行时路径 "/Views" 映射到本地工作区的 "Insurance.Api/Views" 目录
"sourceFileMap": {
"/Views": "${workspaceFolder}/xxxProject/Views"
}
}
]
}
1.2 task.json 文件配置
task.json
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
{
"version": "2.0.0",
// demo 共配置了两个任务 win F1 mac fn+F1 run task 选择执行
"tasks": [
// 配置的第一个任务 build-xxx 和 上边 launch.json 中配置的 preLaunchTask 关联 用于launch.json中配置启动项目在启动前先编译项目
{
// 任务的名称,在 VsCode 中引用这个任务时会用到(如在 launch.json 的 preLaunchTask 中)
"label": "build-xxx",
// 要执行的命令,这里是 .NET CLI
"command": "dotnet",
// 任务类型,表示将作为独立进程运行
"type": "process",
// build: 执行构建操作
// ${workspaceFolder}/xxxProject/xxxProject.csproj: 要构建的项目文件路径
// /property:GenerateFullPaths=true: 生成完整路径(便于错误定位)
// /consoleloggerparameters:NoSummary: 控制台输出不显示摘要信息
"args": [
"build",
"${workspaceFolder}/xxxProject/xxxProject.csproj",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
// 使用 VsCode 内置的 MSBuild 问题匹配器,可以解析构建错误和警告
"problemMatcher": "$msCompile"
},
// 配置的第二个任务, 用于发布项目
{
"label": "publish-release-xxx",
"command": "dotnet",
"type": "process",
// 执行参数 当前示例中的参数 都和 dotnet publish 相关。
/*
args: 发布命令的详细参数
publish: 执行发布操作
项目文件路径
-c Release: 使用 Release 配置构建
-p:Platform=AnyCPU: 指定目标平台为 AnyCPU
--framework net8.0: 目标框架是 .NET 8.0
-o /Users/odinsam/gitee/xxx/serverPublish: 输出目录
--self-contained false: 非自包含部署(需要目标机器有 .NET 运行时)
/p:Version=1.0.0: 设置版本号为 1.0.0
/p:DevConfig=xxx: 重要参数!指定开发配置为"xxx"
*/
"args": [
"publish",
"${workspaceFolder}/xxxProject/xxxProject.csproj",
"-c",
"Release",
"-p:Platform=AnyCPU",
"--framework",
"net8.0",
"-o",
"/Users/odinsam/gitee/xxx/serverPublish",
"--self-contained",
"false",
"/p:Version=1.0.0",
"/p:DevConfig=xxx"
],
"problemMatcher": "$msCompile"
}
]
}

2. 在Rider中配置调试

2.1 launchSettings.json 配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
{
"$schema": "http://json.schemastore.org/launchsettings.json",

/*
IIS 设置部分
windowsAuthentication: false - 禁用 Windows 身份验证
anonymousAuthentication: true - 启用匿名身份验证
iisExpress:
applicationUrl: IIS Express 使用的 URL (http://localhost:60716)
sslPort: 0 表示不使用 SSL
*/
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:60716",
"sslPort": 0
}
},
// 配置环境 (profiles) 定义了多个启动配置环境,可以通过 Visual Studio 或 CLI 选择使用哪个配置启动项目。
"profiles": {
// xxxProject 配置 (xxxProject.config)
/*
commandName: "Project" - 直接运行项目(使用 Kestrel 服务器)
launchBrowser: true - 启动后自动打开浏览器
applicationUrl: 应用监听的 URL (http://localhost:8081)
environmentVariables:
ASPNETCORE_ENVIRONMENT: "Development" - 设置环境为开发环境
commandLineArgs: "--devConfig=xxx" - 传递命令行参数,多个参数用 空格 分开
*/
"xxxProject.config": {
"commandName": "Project",
"launchBrowser": true,
"applicationUrl": "http://localhost:8081",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"commandLineArgs": "--devConfig=xxx"
},
// IIS Express 配置
/*
commandName: "IISExpress" - 使用 IIS Express 作为服务器
launchBrowser: true - 启动后自动打开浏览器
environmentVariables:
ASPNETCORE_ENVIRONMENT: "Development" - 开发环境
*/
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

3. 发布项目

3.1 发布项目的配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
<Project Sdk="Microsoft.NET.Sdk.Web">

<!-- 构建时先编译ConfigMerger -->
<!--
自定义构建目标 - BuildConfigMerger
BeforeTargets="BeforeBuild": 在常规构建之前执行
删除发布目录(如果存在)
构建配置合并工具项目
-->
<Target Name="BuildConfigMerger" BeforeTargets="BeforeBuild">
<RemoveDir Directories="$(PublishDir)" Condition="Exists('$(PublishDir)')"/>
<MSBuild Projects="$(ConfigMergerProj)" Targets="Build" Properties="Configuration=$(Configuration)"/>
</Target>

<!-- 发布时合并配置 -->
<!--
自定义发布目标 - MergeAppSettings AfterTargets="Publish": 在发布完成后执行
-->
<Target Name="MergeAppSettings" AfterTargets="Publish">
<PropertyGroup>
<PublishDir>$([MSBuild]::NormalizePath('$(PublishDir)'))</PublishDir>
<!-- 发布项目时 DevConfig对应的参数,发布时可以手动修改参数 -->
<DevConfig Condition="'$(DevConfig)' == ''">xxx</DevConfig>
<MergedConfigFile>$(PublishDir)appsettings.json</MergedConfigFile>
<!-- 要保留的文件名 -->
<ConfigToKeep>appsettings.json</ConfigToKeep>
</PropertyGroup>

<ItemGroup>
<!-- 找到所有appsettings.Development.*.json文件 -->
<AllDevConfigs Include="$(PublishDir)appsettings.Development.*.json"/>

<!-- 筛选出要删除的文件(排除要保留的) -->
<DevConfigsToDelete Include="@(AllDevConfigs)"
Exclude="$(PublishDir)$(ConfigToKeep)"/>
</ItemGroup>

<Message Importance="high" Text="正在合并配置文件: appsettings.json + appsettings.Development.$(DevConfig).json -> $(MergedConfigFile)"/>

<Exec Command="dotnet &quot;$(ConfigMergerDll)&quot; &quot;$(MergedConfigFile)&quot; &quot;$(MergedConfigFile)&quot; &quot;$(PublishDir)appsettings.Development.$(DevConfig).json&quot;"
WorkingDirectory="$(ProjectDir)"/>

<!-- 显示将要删除的文件(调试用) -->
<Message Text="将保留的文件: $(PublishDir)$(ConfigToKeep)" Importance="high"/>
<Message Text="将删除的文件: @(DevConfigsToDelete)" Importance="high"/>
<Message Text="将删除的文件: appsettings.Development.json" Importance="high"/>

<!-- 执行删除 -->
<Delete Files="@(DevConfigsToDelete)"/>
<Delete Files="$(PublishDir)appsettings.Development.json"/>
</Target>


<PropertyGroup>
<OutputType>Exe</OutputType>
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
<LangVersion>latest</LangVersion>
<ErrorOnDuplicatePublishOutputFiles>false</ErrorOnDuplicatePublishOutputFiles>
<TargetFramework>net8.0</TargetFramework>
<!--<AspNetCoreHostingModel>OutOfProcess</AspNetCoreHostingModel>-->
<!--
配置合并工具路径
ConfigMergerDir: 合并工具项目目录
ConfigMergerProj: 合并工具项目文件路径
ConfigMergerDll: 合并工具生成的 DLL 路径
--> <ConfigMergerDir>$([MSBuild]::NormalizePath('$(MSBuildThisFileDirectory)..', 'ConfigMerger/'))</ConfigMergerDir>
<ConfigMergerProj>$([MSBuild]::NormalizePath('$(ConfigMergerDir)', 'ConfigMerger.csproj'))</ConfigMergerProj>
<ConfigMergerDll>$([MSBuild]::NormalizePath('$(ConfigMergerDir)', 'bin/$(Configuration)/net8.0/ConfigMerger.dll'))</ConfigMergerDll>

</PropertyGroup>
</Project>
3.2 合并配置文件的帮助类

创建控制台项目 ConfigMerger

Program.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
using Newtonsoft.Json.Linq;

if (args.Length < 3)
{
Console.WriteLine("Usage: ConfigMerger <outputFile> <baseConfig> <overrideConfig>");
return 1;
}

try
{
// e.g /Users/odinsam/gitee/zb/xxx/serverPublish/appsettings.json
var outputFile = args[0];
// e.g /Users/odinsam/gitee/zb/xxx/serverPublish/appsettings.json
var baseConfig = args[1];
// e.g /Users/odinsam/gitee/zb/xxx/serverPublish/appsettings.Development.xxx.json
var overrideConfig = args[2];

// 读取基础配置
var baseJson = File.Exists(baseConfig)
? JObject.Parse(File.ReadAllText(baseConfig))
: new JObject();

// 读取覆盖配置
if (File.Exists(overrideConfig))
{
var overrideJson = JObject.Parse(File.ReadAllText(overrideConfig))!;
MergeJsonObjects(baseJson, overrideJson);
}

// 写入合并后的文件
Directory.CreateDirectory(Path.GetDirectoryName(outputFile));
File.WriteAllText(outputFile, baseJson.ToString(Newtonsoft.Json.Formatting.Indented));

return 0;
}
catch (Exception ex)
{
Console.WriteLine($"Error merging configs: {ex.Message}");
return 1;
}

static void MergeJsonObjects(JObject target, JObject source)
{
foreach (var property in source.Properties())
{
if (property.Value is JObject sourceObj &&
target.TryGetValue(property.Name, out var targetValue) &&
targetValue is JObject targetObj)
{
MergeJsonObjects(targetObj, sourceObj);
}
else
{
target[property.Name] = property.Value?.DeepClone();
}
}
}