PAYATHON 2026

VS Code 中 dotnet run 与 Debugger 的运行结果为何不同

排障赵师傅

结论

如果启动项目、构建配置、工作目录、环境变量和启动配置相同,dotnet run 与 VS Code Debugger 运行的应当是同一个 ASP.NET Core 应用,结果也应一致。

目前的现象可能由几个问题共同造成:

  1. dotnet run 启动的进程尚未完全停止,Debugger 又在同一输出目录中构建项目,导致 obj 中的引用程序集不完整。
  2. Debugger 的 program、cwd 或启动项目配置有误,因而启动了错误的 DLL,或者运行目录中缺少 .runtimeconfig.json 和 .deps.json。
  3. Debugger 使用了不同的 Content Root、环境或端口,没有加载本地 scaffold 的 Identity 页面。浏览器也可能仍在访问另一个进程。
  4. 第一次失败留下了不完整的构建输出。后续启动分别使用残留文件和重新生成的文件,所以连续三次出现了不同结果。

这些现象不属于调试器的正常行为,目前也没有足够证据指向 Flatpak。Rider 和非 Flatpak 版 VS Code 都出现相同问题,更应该先检查项目、输出目录和启动配置。

Model.dll 为什么会从 obj 中消失

obj/Debug/net10.0/ref/Model.dll 是供编译器使用的引用程序集,应用运行时不会加载它。清理或重新构建 Model 项目时,该文件可能先被删除,然后重新生成。

如果此时另一个构建任务正在编译 Web 或 Service,就可能出现以下错误:

CSC : error CS0006: Metadata file .../obj/Debug/net10.0/ref/Model.dll could not be found

常见原因有:

  • dotnet run 和 Debugger 同时构建同一项目。
  • 多个 IDE 同时打开并构建同一个解决方案。
  • Debugger 配置了重复的构建任务。
  • 上一次构建被中断,obj 目录中留下了不完整的文件。
  • 项目文件通过 HintPath 直接引用了 obj 中的 DLL。
  • 多个项目共用同一个中间输出目录。

项目之间应使用 ProjectReference,不要直接引用 obj 或 bin 中的 DLL。例如:

<ItemGroup>
  <ProjectReference Include="../Service/Service.csproj" />
  <ProjectReference Include="../Model/Model.csproj" />
</ItemGroup>

检查项目文件中是否有类似配置:

<Reference Include="Model">
  <HintPath>../Model/obj/Debug/net10.0/ref/Model.dll</HintPath>
</Reference>

如果有,请删除这种 DLL 引用,改用 ProjectReference。

同时存在 Web -> Service -> Model 和 Web -> Model 没有问题,但项目之间不能形成 Model -> Web 之类的循环引用。

libhostpolicy.so 错误是怎么产生的

框架依赖型 .NET 应用的输出目录通常至少有以下文件:

Web.dll
Web.deps.json
Web.runtimeconfig.json

如果 Debugger 指向了错误的 DLL 或目录,或者构建失败后只生成了 Web.dll,缺少对应的 .runtimeconfig.json,.NET Host 可能错误判断应用的启动方式,随后报告:

The library 'libhostpolicy.so' required to execute the application was not found
Failed to run as a self-contained app.

遇到这种情况,先不要复制或安装 libhostpolicy.so。应确认 Debugger 实际启动了哪个文件,并检查同一目录下是否有对应的运行时配置文件:

ls -l Web/bin/Debug/net10.0/Web.dll
ls -l Web/bin/Debug/net10.0/Web.deps.json
ls -l Web/bin/Debug/net10.0/Web.runtimeconfig.json

还要确认 program 没有被误设为 SDK 目录、项目目录或其他类库项目的 DLL。

明确配置 VS Code 的启动方式

工作区中的自动推断结果可能已经失效,建议为 Web 项目设置明确的构建任务。

.vscode/tasks.json:

{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "build Web",
      "type": "process",
      "command": "dotnet",
      "args": [
        "build",
        "${workspaceFolder}/Web/Web.csproj",
        "--configuration",
        "Debug"
      ],
      "problemMatcher": "$msCompile",
      "group": {
        "kind": "build",
        "isDefault": true
      }
    }
  ]
}

.vscode/launch.json:

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Debug Web",
      "type": "coreclr",
      "request": "launch",
      "preLaunchTask": "build Web",
      "program": "${workspaceFolder}/Web/bin/Debug/net10.0/Web.dll",
      "args": [],
      "cwd": "${workspaceFolder}/Web",
      "stopAtEntry": false,
      "env": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      },
      "serverReadyAction": {
        "action": "openExternally",
        "pattern": "\\bNow listening on:\\s+(https?://\\S+)"
      }
    }
  ]
}

目录名称需要根据实际项目结构调整。配置时注意以下几点:

  • preLaunchTask 只构建一次 Web.csproj。
  • program 指向 Web 的 Debug 输出。
  • cwd 指向 Web 项目目录。
  • ASPNETCORE_ENVIRONMENT 与命令行启动时一致。
  • program 中的目标框架与项目实际的 TargetFramework 一致。

如果 dotnet run 使用了 Properties/launchSettings.json 中的特定 profile,Debugger 也要使用相同的环境变量、URL 和其他参数。可以先运行一条参数明确的命令,确认基准行为:

dotnet run \
  --project Web/Web.csproj \
  --configuration Debug \
  --launch-profile https

这里的 https 只是示例,请替换为 launchSettings.json 中实际存在的 profile 名称。

Debugger 为什么显示默认注册页面

ASP.NET Core Identity scaffold 的页面通常位于:

Web/Areas/Identity/Pages/Account/Register.cshtml
Web/Areas/Identity/Pages/Account/Register.cshtml.cs

页面文件应为 Register.cshtml,而不是普通的 Register.html。应用找不到本地页面时,会退回到 Identity Razor Class Library 提供的默认页面。

逐项检查以下配置:

  • 页面是否位于启动项目 Web 的 Areas/Identity/Pages/Account 目录。
  • Web.csproj 是否使用 Microsoft.NET.Sdk.Web。
  • Register.cshtml 和 Register.cshtml.cs 的命名空间、@page 与 @model 是否匹配。
  • RegisterModel 是否使用自定义用户类型,例如 UserManager<ApplicationUser>。
  • Debugger 的 cwd 和 Content Root 是否指向 Web 项目。
  • Debugger 与 dotnet run 是否使用相同的环境和启动 profile。
  • 浏览器打开的是否为当前调试进程输出的地址,而不是之前 dotnet run 使用的端口。

页面模型中的用户类型应保持一致。例如:

public class RegisterModel : PageModel
{
    private readonly UserManager<ApplicationUser> _userManager;
    private readonly SignInManager<ApplicationUser> _signInManager;

    public RegisterModel(
        UserManager<ApplicationUser> userManager,
        SignInManager<ApplicationUser> signInManager)
    {
        _userManager = userManager;
        _signInManager = signInManager;
    }
}

服务注册也要使用相同的类型:

builder.Services
    .AddDefaultIdentity<ApplicationUser>(options =>
    {
        options.SignIn.RequireConfirmedAccount = true;
    })
    .AddEntityFrameworkStores<ApplicationDbContext>();

如果 Debugger 启动的是另一个 Web 项目、旧输出,或者使用了错误的 Content Root,本地 scaffold 页面就无法覆盖 Identity 自带的页面。

清理后按固定流程验证

先停止 VS Code、Rider 和终端中所有正在运行的应用实例,然后执行:

dotnet clean Web/Web.csproj --configuration Debug
dotnet build Web/Web.csproj --configuration Debug
dotnet run --project Web/Web.csproj --configuration Debug --no-build

确认这些命令可以正常运行后,停止应用,再按 F5。不要同时让 dotnet run 和 Debugger 构建同一套 bin、obj 目录。

还可以检查残留进程和被占用的端口:

ps -ef | grep '[d]otnet'
ss -ltnp

终止进程前先核对 PID,以免误结束其他 .NET 服务。

附加到 dotnet run 启动的进程

如果暂时找不到 Launch 配置的问题,可以用 dotnet run 启动应用,再让 VS Code 附加到该进程。这样既能沿用已经验证可用的启动方式,也可以正常使用断点。

在 launch.json 中添加:

{
  "name": "Attach to .NET Process",
  "type": "coreclr",
  "request": "attach",
  "processId": "${command:pickProcess}"
}

操作步骤如下:

  1. 在终端运行 dotnet run --project Web/Web.csproj。
  2. 在 VS Code 中选择 Attach to .NET Process。
  3. 选择对应的 Web 进程。
  4. 设置断点并开始调试。

还需要提供哪些信息

仅凭现有错误信息,暂时无法判断具体是哪项配置导致了问题。如果完成上述检查后,Debugger 与 dotnet run 的行为仍不一致,请提供:

  • .vscode/launch.json
  • .vscode/tasks.json
  • Web/Properties/launchSettings.json
  • 三个项目的 .csproj
  • dotnet --info 输出
  • Debug Console 中完整的启动命令和构建日志
  • scaffold 后 Areas/Identity 的目录结构
  • Debugger 与 dotnet run 各自监听的 URL

根据这些信息,通常可以判断问题来自重复构建、启动路径错误、环境差异,还是 Identity 页面的路径或用户类型配置。

备注:内容仅供参考。