Fix ASP.NET Core Debug Exit with Proper VS Code Launch Setup

Summary

The API exits instantly when launched from VS Code’s debugger because the host process is being started as a console application without the ASP.NET Core web host infrastructure. The debugger’s launch configuration runs the DLL directly, bypassing the WebApplication builder that starts Kestrel and waits for HTTP requests. As a result, the process starts, registers the hosted service, runs the migration, and then terminates with exit code 0.


Root Cause

  • Launch configuration points to the raw DLL (Kumi.API.dll) instead of invoking dotnet run with the web host arguments.
  • WebApplication.CreateBuilder is never called, so no IHost with a web server is constructed.
  • The hosted service (KumiRuntime) completes its StartAsync method, the application has nothing else to do, and the runtime exits cleanly.

Why This Happens in Real Systems

  • VS Code’s C# Dev Kit generates a generic “coreclr” launch that works for console apps but not automatically for ASP.NET Core web projects.
  • When developers copy the generated launch.json without customizing the launchBrowser / serverReadyAction or program fields, the debugger launches the assembly as a plain console app.
  • In larger solutions with multiple projects (API, Core, Persistence), the mistake is easy to miss because dotnet run works, hiding the mis‑configuration until debugging.

Real-World Impact

  • Zero traffic: The API never starts listening, so downstream services, CI pipelines, or integration tests fail with “connection refused”.
  • False positives: Exit code 0 makes it look like a successful run, leading teams to chase unrelated symptoms (database connectivity, environment variables).
  • Wasted debugging time: Engineers waste hours investigating migration or DI issues that aren’t the real problem.

Example or Code (if necessary and relevant)

{
  "name": ".NET Core Launch (web)",
  "type": "coreclr",
  "request": "launch",
  "preLaunchTask": "build",
  "program": "${workspaceFolder}/Kumi.API/bin/Debug/net10.0/Kumi.API.dll",
  "cwd": "${workspaceFolder}/Kumi.API",
  "serverReadyAction": {
    "action": "openExternally",
    "pattern": "\\bNow listening on:\\s+(https?://\\S+)"
  }
}

How Senior Engineers Fix It

  • Switch to the proper ASP.NET Core launch template:
    {
      "name": ".NET Core Launch (web)",
      "type": "coreclr",
      "request": "launch",
      "preLaunchTask": "build",
      "program": "${workspaceFolder}/Kumi.API/bin/Debug/net10.0/Kumi.API.dll",
      "args": [],
      "cwd": "${workspaceFolder}/Kumi.API",
      "env": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      },
      "console": "internalConsole",
      "stopAtEntry": false,
      "launchBrowser": {
        "enabled": true,
        "args": "${auto-detect-url}"
      },
      "serverReadyAction": {
        "action": "openExternally",
        "pattern": "\\bNow listening on:\\s+(https?://\\S+)"
      }
    }
  • Add "launchBrowser" and ensure "console": "internalConsole" so VS Code knows it’s a web app.
  • Verify that Program.cs uses WebApplication.CreateBuilder(args) and calls app.Run();.
  • Run the debugger; Kestrel spins up, the hosted service runs, and the process stays alive waiting for HTTP requests.

Why Juniors Miss It

  • Assume the generated launch config works for all .NET projects – they don’t realize the distinction between console and web hosts.
  • Focus on code errors (DI, migration) rather than the surrounding tooling configuration.
  • Limited exposure to VS Code’s debugging internals; they rarely inspect the launch.json after the initial generation.
  • Confidence in “exit code 0 = success” leads them to overlook that the process simply has nothing left to do.

Leave a Comment