CodeOath
← All posts
.NET Core / Web API70 min total · 19 parts

Building REST APIs with ASP.NET Core: Routing, Middleware, and Dependency Injection

Contents — Part 14 of 19: Error Handling and ProblemDetails
Part 14 of 19 · ~1 min

Error Handling and ProblemDetails

Returning a raw, unhandled exception's message to a client leaks internal implementation details (stack traces, connection strings in an exception message, internal type names) and gives the caller nothing structured to handle programmatically. The standard fix is centralized exception-handling middleware that converts any unhandled exception into a consistent ProblemDetails response:

if (app.Environment.IsDevelopment())
{
    app.UseDeveloperExceptionPage(); // detailed errors, safe ONLY for local development
}
else
{
    app.UseExceptionHandler(errorApp =>
    {
        errorApp.Run(async context =>
        {
            context.Response.StatusCode = StatusCodes.Status500InternalServerError;
            context.Response.ContentType = "application/problem+json";
            var problem = new ProblemDetails
            {
                Status = 500,
                Title = "An unexpected error occurred.",
                // deliberately no exception message/stack trace exposed to the client
            };
            await context.Response.WriteAsJsonAsync(problem);
        });
    });
}

ProblemDetails (from RFC 7807) is the standardized JSON shape ASP.NET Core already uses automatically for [ApiController] validation failures — reusing it for unhandled exceptions too keeps every error response from the API in one consistent, machine-parseable shape, rather than validation errors looking nothing like server errors.