ASP.NET Core - Fundamentals - Error Handling

Published: (December 12, 2025 at 11:41 PM EST)
2 min read
Source: Dev.to

Source: Dev.to

1. Use try‑catch block

Best practice when re‑throwing exceptions

  • throw ex; – loses the original stack trace on downstream layers.
  • throw; – preserves the original stack trace, so the API layer receives detailed information.

Only re‑throw (throw;) at lower levels. Creating a new exception (throw new Exception() or a custom exception) also discards the original stack trace.


2. Use custom middleware to centralize exception handling

/// Step 1: Create a middleware class
public class CustomExceptionHandlerMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger _logger;

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

    public async Task InvokeAsync(HttpContext context)
    {
        try
        {
            await _next(context);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error while processing your request");
            await HandleExceptionAsync(context, ex);
        }
    }

    private Task HandleExceptionAsync(HttpContext context, Exception exception)
    {
        context.Response.ContentType = "application/json";
        context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
        return context.Response.WriteAsync(exception.Message);
    }
}

/// Step 2: Create an extension method to use the middleware
public static class CustomExceptionHandlerMiddlewareExtensions
{
    public static IApplicationBuilder UseCustomExceptionHandlers(this IApplicationBuilder app)
    {
        return app.UseMiddleware();
    }
}

3. Centralize exception handling with IExceptionFilter

Implement an ExceptionFilter class

Implement ExceptionFilter class

Register the filter (ASP.NET Core 3.0 sample)

Configure Custom Exception filter

Throw an exception when needed

Exception throwing


4. Use IExceptionHandler (ASP.NET Core 8)

Implement IExceptionHandler

public class GlobalExceptionHandler : IExceptionHandler
{
    private readonly ILogger _logger;

    public GlobalExceptionHandler(ILogger logger)
    {
        _logger = logger;
    }

    public async ValueTask<bool> TryHandleAsync(
        HttpContext httpContext,
        Exception exception,
        CancellationToken cancellationToken)
    {
        _logger.LogError(exception, "Exception occurred: {Message}", exception.Message);

        var problemDetails = new ProblemDetails
        {
            Status = StatusCodes.Status500InternalServerError,
            Title = "Server error -- apply IExceptionHandler for Global"
        };

        httpContext.Response.StatusCode = problemDetails.Status.Value;

        await httpContext.Response.WriteAsJsonAsync(problemDetails, cancellationToken);

        return true; // handled
    }
}

Register and use the handler in Program.cs

// Register the exception handler
builder.Services.AddExceptionHandler();
builder.Services.AddProblemDetails();

var app = builder.Build();

// Activate the handler
app.UseExceptionHandler();
Back to Blog

Related posts

Read more »

Checkbox Aria TagHelper

Introduction Learn how to initialize all checkbox inputs that reside in an ASP.NET Core page using a custom TagHelper. The TagHelper evaluates the checked attr...