Slider

Implement Custom Global Exception Handling in ASP.NET Core.

Explore ASP.NET Core exception handling options—try–catch, UseExceptionHandler, custom middleware, and IExceptionHandler—with pros, cons, and best pra
Exception handling is one of the most important non-functional requirements (NFRs) in any backend application. In ASP.NET Core, poor exception handling leads to:
  • Application crashes
  • Inconsistent error responses
  • Security risks (stack traces exposed)
  • Difficult debugging and monitoring
To solve this, ASP.NET Core promotes Global Exception Handling, where all unhandled exceptions are caught at a single place, logged, and converted into a consistent HTTP response.

This article explains:
  • Why is global exception handling needed
  • How to implement a custom global exception middleware
  • Best practices used in production systems

Why Do We Need Global Exception Handling?

Before understanding Global Exception, we need to know what an exception is and why we need to handle it properly.

An exception is a runtime error that occurs when the application cannot continue normal execution.
Examples:
  • Database connection failure
  • Null reference access
  • Invalid user input
  • External API timeout

If exceptions are not handled properly, they can:
  • Crash the application
  • Leak sensitive information
  • Return inconsistent responses
  • Make debugging extremely difficult
Global Exception Handling is a centralized mechanism that:
  • Catches all unhandled exceptions in one place
  • Logs them consistently
  • Converts them into a standard HTTP response
  • Prevents sensitive details from reaching clients
Instead of handling errors locally in every controller or method, the application handles them globally.

Let's understand the benefits of Global Exception Handling in detail with an example:

Example 1: Error Message Without Global Exception Handler.
{
  "error": "Object reference not set to an instance of an object"
}

Worse Case:
System.NullReferenceException at OrderService.cs line 42
Issues
  • Internal code details exposed
  • Frontend doesn’t know how to handle different formats
  • Logs may be missing or incomplete
Example 2: Error Message With Global Exception Handler.
{
  "statusCode": 400,
  "message": "Invalid request",
  "traceId": "abc123"
}
APIs always return a consistent response.

Imagine a building security desk:
  • Without global handling → every room handles its own security
  • With global handling → one central security desk handles all issues
This is exactly how Global Exception Handling works.
Interview Answer: Global exception handling is needed to centrally catch all unhandled exceptions, return consistent and secure error responses, improve maintainability, and enable reliable logging without duplicating try–catch blocks across the application.

 How To Handle Exceptions in ASP.NET Core?

ASP.NET Core provides multiple ways to handle exceptions, but not all are equal. A senior .NET developer is expected to choose the right approach based on maintainability, security, and scalability.

1. Try-Catch Block in Controller: Handling exceptions inside each controller action using try–catch.

[HttpGet("{id}")]
public IActionResult GetProduct(int id)
{
    try
    {
        var product = _service.GetProduct(id);
        return Ok(product);
    }
    catch (Exception ex)
    {
        return StatusCode(500, ex.Message);
    }
}
Problem:
  • Code duplication: try–catch in every action
  • Inconsistent responses: Different error formats
  • Security risk: Exception messages exposed
  • Poor separation: Business + error handling mixed
  • Hard to maintain: Changes needed everywhere

2. UseExceptionHandler() Middleware: Built-in middleware provided by ASP.NET Core for basic global exception handling.
app.UseExceptionHandler(errorApp =>
{
    errorApp.Run(async context =>
    {
        context.Response.StatusCode = 500;
        await context.Response.WriteAsync("Something went wrong");
    });
});
Problem:
  • Limited customization
  • No exception type mapping
  • No structured response
  • Not ideal for APIs
3. Custom Exception Middleware: A custom middleware that intercepts all unhandled exceptions, logs them, and returns a standard response.

Step 1: Create Custom Exceptions.
public class NotFoundException : Exception
{
    public NotFoundException(string message) : base(message) { }
}

Step 2: Create Error Response Model.
public class ErrorResponse
{
    public int StatusCode { get; set; }
    public string Message { get; set; }
    public string TraceId { get; set; }
}

Step 3: Create Middleware
public class GlobalExceptionMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger<GlobalExceptionMiddleware> _logger;

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

    public async Task InvokeAsync(HttpContext context)
    {
        try
        {
            await _next(context);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Unhandled exception");

            int statusCode = ex switch
            {
                NotFoundException => 404,
                _ => 500
            };

            var response = new ErrorResponse
            {
                StatusCode = statusCode,
                Message = statusCode == 500 ? "Internal error" : ex.Message,
                TraceId = context.TraceIdentifier
            };

            context.Response.StatusCode = statusCode;
            context.Response.ContentType = "application/json";
            await context.Response.WriteAsJsonAsync(response);
        }
    }
}

Step 4: Register Middleware
app.UseMiddleware<GlobalExceptionMiddleware>();

4. IExceptionHandler: A new interface-based global exception handling mechanism introduced in .NET 7.

Step 1: Step 1: Implement IExceptionHandler.
public class GlobalExceptionHandler : IExceptionHandler
{
    public async ValueTask<bool> TryHandleAsync(
        HttpContext context,
        Exception exception,
        CancellationToken cancellationToken)
    {
        context.Response.StatusCode = exception switch
        {
            NotFoundException => 404,
            _ => 500
        };

        await context.Response.WriteAsJsonAsync(new
        {
            message = "Error occurred",
            traceId = context.TraceIdentifier
        }, cancellationToken);

        return true;
    }
}

Step 2: Register Service.
builder.Services.AddExceptionHandler<GlobalExceptionHandler>();

Step 3: Enable Middleware.
app.UseExceptionHandler();

Benefits:
  • Clean & structured
  • Official Microsoft approach
  • Easy integration with ProblemDetails
  • Less boilerplate
Interview Answer: For production-grade ASP.NET Core APIs, I prefer custom global exception middleware because it gives full control over exception mapping, logging, and response structure. For newer .NET versions, IExceptionHandler is also a clean and modern alternative.
0

No comments

Post a Comment

both, mystorymag

DON'T MISS

Tech News
© all rights reserved
made with by AlgoLesson
Table of Contents