I wanted the detailed exception page (stack trace and all) in UAT, but never in production. I had been using a custom ResolvDebug setting for this, which turned out to be on by default in appsettings.json, so prod was quietly showing stack traces. This is the standard way to do it instead, with ASPNETCORE_ENVIRONMENT.
1. Switch on the environment in Program.cs
1 | if (app.Environment.IsDevelopment() || app.Environment.IsEnvironment("Uat")) |
IsDevelopment() and IsProduction() are built in, any other name goes through IsEnvironment("<name>"). If ASPNETCORE_ENVIRONMENT is not set at all, the default is Production, which is the safe way round.
Docs: Use multiple environments
2. Set it per deployment
In my UAT GitHub Actions workflow it is one more environment variable on the container app deploy:
1 | environmentVariables: | |
Prod sets ASPNETCORE_ENVIRONMENT=Production and locally launchSettings.json sets Development. The name can be anything, Uat and Staging both work, just match it in IsEnvironment(...).
As a bonus, appsettings.Uat.json now layers over appsettings.json for UAT only if you ever need UAT specific settings.
3. Add a route that throws
You need a way to prove it, so I have an action that always blows up:
1 | // Test endpoint to force an exception and check the error page |
Hit /Home/TestError in each environment:
- UAT: the detailed exception page with the stack trace.
- Prod: only the generic error page, no stack trace.
Mine sits behind the sign-in the app requires by default, so I have to be logged in to hit it. Consider locking it to an admin policy or removing it once you have checked prod.
Docs: Handle errors in ASP.NET Core
Things to know
- Setting a custom environment name means
IsDevelopment()is false there, so check anything else that treats “not Development” as production. - Deciding the environment from the request host (I had an
EnvironmentResolverdoing this) is fragile, a new domain and it silently says “dev”. Use the environment variable instead.