ASP.NET Core  

How to Handle Exceptions Globally in ASP.NET Core

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.