I have my ASP.NET Core 9 Web API app using custom ExceptionHandlerMiddleware
Middleware to handle all exceptions as shown below:
public sealed class ExceptionHandlerMiddleware(IWebHostEnvironment env, ILogger<ExceptionHandlerMiddleware> logger) : IMiddleware
{
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
try
{
await next(context);
}
catch (DomainException ex)
{
await HandleDomainExceptionAsync(context, ex);
}
catch (DbUpdateException ex)
{
await HandleDbUpdateExceptionAsync(context, ex);
}
catch (Exception ex)
{
await HandleExceptionAsync(context, ex);
}
}
private Task HandleDomainExceptionAsync(HttpContext context, DomainException exception)
{
logger.LogCritical(exception, exception.Message);
var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
string result = JsonSerializer.Serialize(Envelope.Error(exception.Message), options);
context.Response.ContentType = MediaTypeNames.Application.Json;
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
return context.Response.WriteAsync(result);
}
private Task HandleDbUpdateExceptionAsync(HttpContext context, Exception exception)
{
logger.LogCritical(exception, exception.Message);
var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
string result = JsonSerializer.Serialize(Envelope.Error("Error occurred while saving data. Please try again later."), options);
context.Response.ContentType = MediaTypeNames.Application.Json;
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
return context.Response.WriteAsync(result);
}
private Task HandleExceptionAsync(HttpContext context, Exception exception)
{
logger.LogCritical(exception, exception.Message);
var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
string result = env.IsLocal() ? JsonSerializer.Serialize(Envelope.Error(exception.Message), options) : JsonSerializer.Serialize(Envelope.Error("An unexpected fault happened. Try again later."), options);
context.Response.ContentType = MediaTypeNames.Application.Json;
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
return context.Response.WriteAsync(result);
}
}
Now, I came across ProblemDetails
and looks like ASP.NET Core 9 has support for it.
All I need to do is to,
Program.cs:
builder.Services.AddProblemDetails();
var app = builder.Build();
app.UseExceptionHandler();
app.Run();
The setup is easy and straight forward. But the problem is whenever I test with exception I get the below response.
{
"type": ".6.1",
"title": "An error occurred while processing your request.",
"status": 500,
"traceId": "00-a2cfefb5c6ca44a142d9810fef0e5f7d-d7103986bf2c06a4-00"
}
Now I need help in understanding how to show StackTrace
in lower environments like Local
, Offline
, Development
. I'm not able to find an option to configure StackTrace
based on environment.
I checked the problem details docs and not able to find any information.
I have my ASP.NET Core 9 Web API app using custom ExceptionHandlerMiddleware
Middleware to handle all exceptions as shown below:
public sealed class ExceptionHandlerMiddleware(IWebHostEnvironment env, ILogger<ExceptionHandlerMiddleware> logger) : IMiddleware
{
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
try
{
await next(context);
}
catch (DomainException ex)
{
await HandleDomainExceptionAsync(context, ex);
}
catch (DbUpdateException ex)
{
await HandleDbUpdateExceptionAsync(context, ex);
}
catch (Exception ex)
{
await HandleExceptionAsync(context, ex);
}
}
private Task HandleDomainExceptionAsync(HttpContext context, DomainException exception)
{
logger.LogCritical(exception, exception.Message);
var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
string result = JsonSerializer.Serialize(Envelope.Error(exception.Message), options);
context.Response.ContentType = MediaTypeNames.Application.Json;
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
return context.Response.WriteAsync(result);
}
private Task HandleDbUpdateExceptionAsync(HttpContext context, Exception exception)
{
logger.LogCritical(exception, exception.Message);
var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
string result = JsonSerializer.Serialize(Envelope.Error("Error occurred while saving data. Please try again later."), options);
context.Response.ContentType = MediaTypeNames.Application.Json;
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
return context.Response.WriteAsync(result);
}
private Task HandleExceptionAsync(HttpContext context, Exception exception)
{
logger.LogCritical(exception, exception.Message);
var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
string result = env.IsLocal() ? JsonSerializer.Serialize(Envelope.Error(exception.Message), options) : JsonSerializer.Serialize(Envelope.Error("An unexpected fault happened. Try again later."), options);
context.Response.ContentType = MediaTypeNames.Application.Json;
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
return context.Response.WriteAsync(result);
}
}
Now, I came across ProblemDetails
and looks like ASP.NET Core 9 has support for it.
All I need to do is to,
Program.cs:
builder.Services.AddProblemDetails();
var app = builder.Build();
app.UseExceptionHandler();
app.Run();
The setup is easy and straight forward. But the problem is whenever I test with exception I get the below response.
{
"type": "https://tools.ietf./html/rfc9110#section-15.6.1",
"title": "An error occurred while processing your request.",
"status": 500,
"traceId": "00-a2cfefb5c6ca44a142d9810fef0e5f7d-d7103986bf2c06a4-00"
}
Now I need help in understanding how to show StackTrace
in lower environments like Local
, Offline
, Development
. I'm not able to find an option to configure StackTrace
based on environment.
I checked the problem details docs and not able to find any information.
First of all, default template for ASP.NET Core project contains such lines:
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.MapOpenApi();
app.UseDeveloperExceptionPage();
}
which enables developer exception page in development mode. This page contains stack trace for example:
If I would comment/remove app.UseDeveloperExceptionPage()
, then i would get this in browser (this is just response body):
So, this is one way to get more details about exceptions.
You can adjust behavior of problem details with such overload of AddProblemDetails
:
builder.Services.AddProblemDetails(options =>
{
options.CustomizeProblemDetails = context =>
{
var hostEnv = context.HttpContext.RequestServices.GetRequiredService<IHostEnvironment>();
var shouldIncludeStackTrace = hostEnv.IsDevelopment();
if (context.Exception is null || !shouldIncludeStackTrace)
{
return;
}
context.ProblemDetails.Detail = context.Exception.StackTrace;
};
});
With this change, you will get additional stack trace in details
property in response, only in development environment:
Last, but not least, you need to adjust condition:
var shouldIncludeStackTrace = hostEnv.IsDevelopment();
in order to inlcude stack trace only in environments, that need it.
CustomizeProblemDetails