DEV Community

Cover image for Global Exception Handling in .NET Web API
Harpreet Singh
Harpreet Singh

Posted on

Global Exception Handling in .NET Web API

When building APIs, one of the most common mistakes developers make is scattering try-catch blocks across controllers. Not only does this make the code messy, but it also leads to inconsistent error responses for clients.

The solution? Global Exception Handling using middleware in .NET Web API.


Why Global Exception Handling?

  • Centralized error management: All exceptions go through one pipeline.
  • Consistent responses: Clients always receive structured error messages.
  • Cleaner controllers: No need for repetitive try-catch blocks.
  • Better logging: Easier to log all unhandled exceptions.

Step 1: Create Exception Handling Middleware

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

    public GlobalExceptionMiddleware(RequestDelegate next, ILogger<GlobalExceptionMiddleware> logger)
    {
        _next = next;
        _logger = logger;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        try
        {
            await _next(context);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Unhandled exception occurred.");
            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
        {
            StatusCode = context.Response.StatusCode,
            Message = "Internal Server Error. Please try again later.",
            Detail = exception.Message // Optional: remove in production
        };

        return context.Response.WriteAsJsonAsync(response);
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 2: Register Middleware in Program.cs

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

// Add global exception middleware
app.UseMiddleware<GlobalExceptionMiddleware>();

app.MapControllers();
app.Run();
Enter fullscreen mode Exit fullscreen mode

Step 3: Testing the Middleware

Add a controller that throws an exception:

[ApiController]
[Route("api/[controller]")]
public class TestController : ControllerBase
{
    [HttpGet("error")]
    public IActionResult GetError()
    {
        throw new InvalidOperationException("This is a test exception.");
    }
}
Enter fullscreen mode Exit fullscreen mode

Call GET /api/test/error and you should get a JSON response like:

{
  "StatusCode": 500,
  "Message": "Internal Server Error. Please try again later.",
  "Detail": "This is a test exception."
}
Enter fullscreen mode Exit fullscreen mode

Step 4: Optional Enhancements

  • Environment-aware messages: Hide Detail in production.
  • Custom exception types: Handle validation exceptions differently.
  • Structured logging: Include correlation IDs for tracing.
  • Problem Details RFC 7807: Return standardized error responses.

Wrapping Up

Global exception handling keeps your Web API clean, consistent, and easier to maintain. By centralizing error management, you free controllers from repetitive try-catch blocks, make logging easier, and ensure clients always receive a predictable response.

This pattern is a must-have for any production-ready .NET Web API.

Top comments (0)