With ProblemDetails (RFC 9457) and a central IExceptionHandler.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | // ====================================================================== // Q: How do you handle errors consistently in an API? // // With ProblemDetails (RFC 9457) and a central IExceptionHandler. Stack traces // never reach the client. // ====================================================================== builder.Services.AddProblemDetails(); builder.Services.AddExceptionHandler<GlobalExceptionHandler>(); public class GlobalExceptionHandler(ILogger<GlobalExceptionHandler> log) : IExceptionHandler { public async ValueTask<bool> TryHandleAsync(HttpContext ctx, Exception ex, CancellationToken ct) { var (status, title) = ex switch { ValidationException => (400, "Validation failed"), NotFoundException => (404, "Not found"), _ => (500, "Unexpected error") }; if (status == 500) log.LogError(ex, "Unhandled exception"); ctx.Response.StatusCode = status; await ctx.Response.WriteAsJsonAsync(new ProblemDetails { Status = status, Title = title, Extensions = { ["traceId"] = ctx.TraceIdentifier } }, ct); return true; } } |