ASP.NET Core Web API

Global Exception Handling Middleware

1 Views Updated 5/4/2026

Global Exception Handling Middleware

Wrapping every single Controller action in a try { ... } catch { return StatusCode(500); } block is an egregious anti-pattern. Not only does it bloat your codebase with redundant code, but it also risks missing errors thrown outside controllers. The architect's solution is a Global Exception Handling Middleware.

1. The Concept of Middleware

Middleware is a pipeline. Every HTTP request enters the pipeline, passes through various middlewares (like Authentication), hits the Controller, and the Response bubbles back out through the identical pipeline. If we put a massive try-catch at the very entrance of the pipeline, it will perfectly catch any exception thrown anywhere in the entire application.

2. Creating the Custom Middleware

We create a class that intercepts the HTTP context, invokes the rest of the application (await _next(context)), and catches any resulting explosions.

using System.Net;
using System.Text.Json;

public class GlobalExceptionMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger<GlobalExceptionMiddleware> _logger;
    private readonly IHostEnvironment _env;

    // _next represents the rest of the application pipeline
    public GlobalExceptionMiddleware(RequestDelegate next, ILogger<GlobalExceptionMiddleware> logger, IHostEnvironment env)
    {
        _next = next;
        _logger = logger;
        _env = env;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        try
        {
            // PROCEED: Let the request traverse the rest of the API
            await _next(context);
        }
        catch (Exception ex)
        {
            // BOOM! An unhandled exception was thrown somewhere!
            _logger.LogError(ex, "An unhandled exception occurred.");
            await HandleExceptionAsync(context, ex);
        }
    }

    private async Task HandleExceptionAsync(HttpContext context, Exception exception)
    {
        // Standardize the API response to always be JSON
        context.Response.ContentType = "application/json";
        context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;

        // Custom Error Object (If in Production, NEVER show the stack trace)
        var response = new 
        {
            StatusCode = context.Response.StatusCode,
            Message = _env.IsDevelopment() ? exception.Message : "An unexpected internal server error occurred.",
            Details = _env.IsDevelopment() ? exception.StackTrace : null
        };

        var json = JsonSerializer.Serialize(response);
        await context.Response.WriteAsync(json);
    }
}

3. Wiring it up in Program.cs

Location in the pipeline is critical. The exception handler MUST be the very first middleware registered so it completely wraps everything below it.

var app = builder.Build();

// 1. MUST BE FIRST IN THE PIPELINE
app.UseMiddleware<GlobalExceptionMiddleware>();

app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();

app.Run();

4. The Modern .NET 8 Alternative: IExceptionHandler

In newer .NET versions, Microsoft introduced an interface-based approach that is slightly cleaner than writing raw middleware.

public class CustomExceptionHandler : IExceptionHandler
{
    public async ValueTask<bool> TryHandleAsync(HttpContext context, Exception exception, CancellationToken cancellationToken)
    {
        // Log it, modify the response, and return true to indicate the exception was handled.
        context.Response.StatusCode = 500;
        await context.Response.WriteAsJsonAsync(new { Error = "Fatal Server Error." }, cancellationToken);
        return true; 
    }
}

// In Program.cs
builder.Services.AddExceptionHandler<CustomExceptionHandler>();
app.UseExceptionHandler(_ => { }); // Activates it in the pipeline

5. Interview Mastery

Q: "If an unhandled exception occurs in a background task (IHostedService), will the Global Exception Handling Middleware catch it?"

Architect Answer: "No. Middleware only exists within the context of an executing HTTP Request pipeline. An `IHostedService` (like a background timer running every 5 minutes) executes entirely outside of the HTTP pipeline. If an unhandled exception occurs inside a background service, the Middleware will never see it. Instead, you must wrap your background task execution logic in its own `try/catch` block. Furthermore, starting in .NET 6, unhandled exceptions in background services will violently crash the entire host process by default (terminating the web server completely) unless the `HostOptions.BackgroundServiceExceptionBehavior` is explicitly configured to Ignore them."

ASP.NET Core Web API
1. Fundamentals & HTTP
Introduction to ASP.NET Core Web API REST Principles and HTTP Methods Controllers & ControllerBase Routing (Attribute vs Conventional) Action Return Types (IActionResult)
2. Request Handling
Model Binding (FromQuery, FromBody, FromRoute) Dependency Injection (DI) Deep Dive App Settings & The Options Pattern
3. Data Access & Architecture
EF Core Setup in Web API DbContext & Migrations Repository & Unit of Work Pattern Asynchronous Programming (async/await)
4. Data Transfer & Validation
Data Transfer Objects (DTOs) & AutoMapper Model Validation (DataAnnotations) FluentValidation Integration
5. Advanced Concepts
Global Exception Handling Middleware Content Negotiation (JSON vs XML) Pagination & Filtering Advanced Searching & Sorting HATEOAS (Hypermedia) Implementation Output Caching & Response Caching
6. Security & Authorization
Cross-Origin Resource Sharing (CORS) JWT Authentication Setup Access Tokens & Refresh Tokens Workflow Role-Based & Policy-Based Authorization API Key Authentication Rate Limiting & Throttling
7. Documentation & Testing
Swagger & OpenAPI Configuration Customizing API Documentation Unit Testing Controllers (xUnit & Moq) Integration Testing (WebApplicationFactory)
8. Microservices & Deployment
Consuming External APIs (IHttpClientFactory) Health Checks & Diagnostics API Versioning Strategies Deploying APIs (Docker & Azure)