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 invokingdotnet runwith the web host arguments. WebApplication.CreateBuilderis never called, so noIHostwith a web server is constructed.- The hosted service (
KumiRuntime) completes itsStartAsyncmethod, 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.jsonwithout customizing thelaunchBrowser/serverReadyActionorprogramfields, 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 runworks, 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.csusesWebApplication.CreateBuilder(args)and callsapp.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.jsonafter the initial generation. - Confidence in “exit code 0 = success” leads them to overlook that the process simply has nothing left to do.