.NET › Global Exception Handling & Middleware
How should a global exception handler differentiate between exceptions that should return specific client-facing details versus exceptions that should always show a generic message?
IntermediateAnswer
A common pattern defines a custom base exception class (like ApiException with a public Message and StatusCode meant for client display) that business logic throws for expected, user-facing error conditions, while any exception NOT inheriting from this base type (unexpected bugs, infrastructure failures) is treated as an internal error and given only a generic message -- this explicit opt-in design prevents accidentally leaking internal exception details for the many exception types never designed to be shown to end users.
public class ApiException : Exception {
public int StatusCode { get; }
public ApiException(string message, int statusCode = 400) : base(message) => StatusCode = statusCode;
}
// In the handler:
var (status, message) = exception is ApiException apiEx
? (apiEx.StatusCode, apiEx.Message) // safe, intentionally client-facing
: (500, "An unexpected error occurred"); // generic for anything elseReal-world example A checkout flow throws a custom InsufficientStockException : ApiException with a clear customer-facing message, while an unrelated database timeout exception (not inheriting ApiException) is automatically shown only as a generic 'something went wrong' message, preventing internal details from leaking.