Global Exception Handling
Implement centralized error handling in your application.
By EMEPublished: February 20, 2025
exception handlingmiddlewareerrorslogging
A Simple Analogy
Global exception handling is like a safety net. Any errors fall through and are caught at the bottom.
Why Global Handling?
- Consistency: Same response format everywhere
- Logging: Centralized error tracking
- Security: Don't expose stack traces
- UX: User-friendly error messages
- Maintenance: One place to fix error handling
Middleware Approach
public class ExceptionHandlingMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<ExceptionHandlingMiddleware> _logger;
public ExceptionHandlingMiddleware(RequestDelegate next, ILogger<ExceptionHandlingMiddleware> logger)
{
_next = next;
_logger = logger;
}
public async Task InvokeAsync(HttpContext context)
{
try
{
await _next(context);
}
catch (Exception ex)
{
_logger.LogError(ex, "Unhandled exception");
await HandleExceptionAsync(context, ex);
}
}
private static Task HandleExceptionAsync(HttpContext context, Exception exception)
{
context.Response.ContentType = "application/json";
var response = exception switch
{
ValidationException ve => new ErrorResponse
{
StatusCode = StatusCodes.Status400BadRequest,
Message = "Validation failed",
Errors = ve.Errors
},
NotFoundException ne => new ErrorResponse
{
StatusCode = StatusCodes.Status404NotFound,
Message = ne.Message
},
_ => new ErrorResponse
{
StatusCode = StatusCodes.Status500InternalServerError,
Message = "An unexpected error occurred"
}
};
context.Response.StatusCode = response.StatusCode;
return context.Response.WriteAsJsonAsync(response);
}
}
// Register
app.UseMiddleware<ExceptionHandlingMiddleware>();
Custom Exception Classes
public class ValidationException : Exception
{
public List<string> Errors { get; }
public ValidationException(List<string> errors)
{
Errors = errors;
}
}
public class NotFoundException : Exception
{
public NotFoundException(string message) : base(message) { }
}
public class UnauthorizedException : Exception
{
public UnauthorizedException(string message) : base(message) { }
}
Error Response Format
public class ErrorResponse
{
public int StatusCode { get; set; }
public string Message { get; set; }
public List<string> Errors { get; set; }
public string TraceId { get; set; }
}
// Usage
var errorResponse = new ErrorResponse
{
StatusCode = 400,
Message = "Invalid request",
Errors = new[] { "Name is required", "Email is invalid" },
TraceId = context.TraceIdentifier
};
Best Practices
- Specific exceptions: Create custom exception types
- Logging: Always log exceptions
- Status codes: Use appropriate HTTP codes
- Security: Don't expose sensitive details
- Consistency: Same format for all errors
Related Concepts
- Try-catch blocks
- Error monitoring
- Logging frameworks
- Recovery strategies
Summary
Implement global exception handling with middleware to catch errors, log them, and return consistent responses.