VSCode 中 .NET 热重载配置详解
在 Visual Studio 中,热重载(Hot Reload)是开箱即用的。但在 VSCode 中,涉及到调试配置、任务配置和扩展的协作,稍不注意就会踩坑。本文梳理 VSCode 下 .NET 项目的调试配置体系,并重点说明热重载的正确开启方式。
VSCode 调试配置基础
VSCode 的调试体系由两个配置文件共同构成:.vscode/launch.json 和 .vscode/tasks.json。
launch.json:定义如何启动/附加调试器
launch.json 支持两种核心模式:
launch 模式:VSCode 直接启动进程并附加调试器。适合本地开发调试。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
"version": "0.2.0",
"configurations": [
{
"name": ".NET Core Launch (web)",
"type": "coreclr",
"request": "launch",
"program": "${workspaceFolder}/bin/Debug/net8.0/MyApp.dll",
"args": [],
"cwd": "${workspaceFolder}",
"env": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
]
}
attach 模式:调试器附加到一个已经在运行的进程上。适合调试容器内进程、远程进程,或由其他方式启动的服务。
1
2
3
4
5
6
{
"name": ".NET Core Attach",
"type": "coreclr",
"request": "attach",
"processId": "${command:pickProcess}"
}
tasks.json:定义构建任务
tasks.json 中定义的任务可以在 launch 之前通过 preLaunchTask 触发,常见用法是先执行 dotnet build 再启动调试:
1
2
3
4
5
6
7
8
9
10
11
12
{
"version": "2.0.0",
"tasks": [
{
"label": "build",
"command": "dotnet",
"type": "process",
"args": ["build", "${workspaceFolder}/MyApp.csproj"],
"problemMatcher": "$msCompile"
}
]
}
热重载的正确配置方式
关键结论
使用 C# Dev Kit 扩展时,不要在 launch.json 中设置 preLaunchTask。
一旦配置了 preLaunchTask,C# Dev Kit 会认为你在自行管理构建流程,从而跳过热重载功能的注入。结果就是:程序能运行,调试器也能附加,但修改代码后没有任何热重载效果。
正确做法
C# Dev Kit 的默认调试方式有两种入口:
- 从解决方案资源管理器右键项目 → 启动调试
- 在
launch.json中配置type: dotnet的启动项
两种方式本质相同。type: dotnet 的启动项配置项较少,基本只能指定启动项目,大多数行为由项目的 launchSettings.json 控制。
将 type 设置为 "dotnet",request 设置为 "launch",不添加 preLaunchTask:
1
2
3
4
5
6
7
8
9
10
11
{
"version": "0.2.0",
"configurations": [
{
"name": "Launch with Hot Reload",
"type": "dotnet",
"request": "launch",
"projectPath": "${workspaceFolder}/MyApp.csproj"
}
]
}
C# Dev Kit 识别到 type: dotnet + request: launch 的组合后,会在启动时自动执行构建,并注入 Hot Reload 支持,无需手动配置 preLaunchTask。
通过 launchSettings.json 启用热重载
C# Dev Kit 默认调试行为会读取项目的 Properties/launchSettings.json。要确保热重载生效,需在对应的 profile 中添加 hotReloadEnabled:
1
2
3
4
5
6
7
8
9
10
11
{
"profiles": {
"MyApp": {
"commandName": "Project",
"hotReloadEnabled": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
多目标框架项目的运行时选择
当项目配置了多目标框架(<TargetFrameworks>)时,Visual Studio 可以在调试栏手动切换运行时版本,但 VSCode 没有此入口。解决方法是修改 .csproj,将希望默认使用的框架版本放到最前面:
1
2
<!-- 调试时将优先使用 net8.0 -->
<TargetFrameworks>net8.0;net6.0</TargetFrameworks>
Razor View 的热重载
注意:
RazorRuntimeCompilation(RRC)的工作机制与 .NET 的 Hot Reload 并不相同——RRC 是在运行时重新编译 Razor 文件,而 Hot Reload 是在调试会话中直接更新托管代码。自 .NET 6 起,官方推荐优先使用 Hot Reload,不再推荐 RRC 作为主要的开发体验。以下配置仅在需要兼容旧方式或特定场景时使用。
对于 ASP.NET Core MVC / Razor Pages 项目,上面的配置只能热重载 C# 代码。.cshtml 文件的修改默认不会生效,需要额外配置运行时编译。
1. 安装 NuGet 包
1
dotnet add package Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation
2. 注册服务
1
2
builder.Services.AddControllersWithViews()
.AddRazorRuntimeCompilation();
3. 条件编译,避免影响生产环境
运行时编译会带来额外开销,不应进入生产构建。使用条件编译将其限制在 DEBUG 模式:
1
2
3
4
5
var mvcBuilder = builder.Services.AddControllersWithViews();
#if DEBUG
mvcBuilder.AddRazorRuntimeCompilation();
#endif
4. 条件引入 NuGet 包(推荐)
为了让 RuntimeCompilation 包不出现在 Release 产物中,可以在 .csproj 中配置条件引入:
1
2
3
<ItemGroup Condition="'$(Configuration)' == 'Debug'">
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="8.0.0" />
</ItemGroup>
这样 Release 构建时既不会编译该包的依赖,也不会将其打入最终产物。与 #if DEBUG 搭配使用,既保证代码编译时不会因缺包报错,又能确保生产产物干净。
排查热重载问题:查看输出日志
如果热重载没有生效,可以在 VSCode 的输出(Output)面板中查看详细日志。
打开方式:菜单 → View → Output,然后在右侧下拉菜单中选择 C# Hot Reload 或 Debugger,即可查看热重载引擎和调试器的运行日志,确认热重载是否被正确注入,以及失败的具体原因。
小结
| 场景 | 做法 |
|---|---|
| C# 代码热重载 | type: dotnet + request: launch,不设置 preLaunchTask |
| 启用热重载 | 在 launchSettings.json 对应 profile 中设置 hotReloadEnabled: true |
| 需要自定义构建步骤 | 用 preLaunchTask,但热重载将失效,需权衡 |
| Razor View 热重载(旧方式) | 安装 RuntimeCompilation 包,条件注册服务(.NET 6+ 推荐改用 Hot Reload) |
| 生产构建不含调试包 | .csproj 中用 Condition 条件引入包 |
| 多目标框架默认运行时 | 在 .csproj 的 <TargetFrameworks> 中将目标框架置于首位 |
| 热重载未生效时排查 | VSCode 输出面板 → 选择 C# Hot Reload 或 Debugger 查看日志 |
在 VSCode 下做 .NET 开发,调试配置的细节比 Visual Studio 多得多。理解 launch / attach 的区别、Dev Kit 的自动构建机制,以及热重载的注入时机,才能避免踩坑。