Handling exceptions globally in ASP.NET Core is essential for building robust, maintainable, and production-ready applications. Instead of scattering try-catch blocks across controllers and services, a centralized approach ensures consistent error handling and cleaner code.
Why Global Exception Handling Matters
Provides consistent error responses
Prevents application crashes
Improves debugging and logging
Keeps controllers and services clean
Approach 1: Using Custom Middleware
Middleware is the most common and recommended way to handle exceptions globally.
Step 1: Create Exception Middleware
using System.Net;
using System.Text.Json;
public class ExceptionMiddleware
{
private readonly RequestDelegate _next;
public ExceptionMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
try
{
await _next(context);
}
catch (Exception ex)
{
await HandleExceptionAsync(context, ex);
}
}
private static Task HandleExceptionAsync(HttpContext context, Exception exception)
{
context.Response.ContentType = "application/json";
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
var response = new
{
message = "An unexpected error occurred.",
detail = exception.Message
};
return context.Response.WriteAsync(JsonSerializer.Serialize(response));
}
}
Step 2: Register Middleware in Pipeline
app.UseMiddleware<ExceptionMiddleware>();
Place this middleware early in the pipeline so it can catch exceptions from all components.
Approach 2: Built-in Exception Handling Middleware
ASP.NET Core provides built-in support for exception handling.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/error");
}
You can define a centralized error endpoint:
app.Map("/error", (HttpContext context) =>
{
return Results.Problem("An error occurred.");
});
Approach 3: Using Filters (For MVC)
Exception filters can be used in MVC applications.
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
public class GlobalExceptionFilter : IExceptionFilter
{
public void OnException(ExceptionContext context)
{
context.Result = new ObjectResult(new
{
message = "Error occurred"
})
{
StatusCode = 500
};
}
}
Register it in Program.cs:
builder.Services.AddControllers(options =>
{
options.Filters.Add<GlobalExceptionFilter>();
});
Best Practices
Do not expose sensitive error details in production
Use structured logging (Serilog, NLog, etc.)
Return standardized error responses
Handle known exceptions separately (e.g., validation errors)
Real-World Example
In a production API:
Middleware handles all unexpected exceptions
Logging captures stack traces
Clients receive clean JSON responses
Example response:
{
"message": "An unexpected error occurred."
}
Common Mistakes to Avoid
Writing try-catch in every controller
Exposing stack traces to users
Not logging exceptions
Registering middleware in the wrong order
Conclusion
Global exception handling in ASP.NET Core simplifies error management and improves application stability. By using middleware or built-in handlers, you can centralize error handling logic, provide consistent responses, and build more maintainable applications.