Monday, 3 August 2026

Using Custom Middleware to Implement Enterprise-Grade Global Exception Handling

Leave a Comment

For reliable production applications, error handling must be done correctly. Using custom middleware or centralized exception handlers,.NET Core enables you to record unhandled exceptions globally rather than encasing each controller action or minimum endpoint handler in repeating try-catch blocks.


This method guarantees that your whole API ecosystem uses the same JSON error response structure.
First, develop a standardized error response model.

To enable frontend clients to parse errors consistently, establish a predictable format for your error payload.

public class ErrorDetails
{
    public int StatusCode { get; set; }
    public string Message { get; set; } = string.Empty;
    public string? Details { get; set; }
    public DateTime Timestamp { get; set; } = DateTime.UtcNow;

    public override string ToString() => System.Text.Json.JsonSerializer.Serialize(this);
}
Step 2: Build the Custom Exception Handling Middleware

Create a middleware component that intercepts exceptions flowing down the HTTP pipeline, logs them securely, and writes a uniform JSON payload back to the client.

using System.Net;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;

public class GlobalExceptionHandlingMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger<GlobalExceptionHandlingMiddleware> _logger;
    private readonly IWebHostEnvironment _env;

    public GlobalExceptionHandlingMiddleware(
        RequestDelegate next,
        ILogger<GlobalExceptionHandlingMiddleware> logger,
        IWebHostEnvironment env)
    {
        _next = next;
        _logger = logger;
        _env = env;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        try
        {
            // Move to the next middleware in the pipeline
            await _next(context);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "An unhandled exception occurred during execution: {Message}", ex.Message);
            await HandleExceptionAsync(context, ex);
        }
    }

    private async Task HandleExceptionAsync(HttpContext context, Exception exception)
    {
        context.Response.ContentType = "application/json";

        // Default to Internal Server Error
        var statusCode = (int)HttpStatusCode.InternalServerError;
        var message = "An internal server error has occurred.";

        // Custom domain or validation exceptions can be handled explicitly here
        if (exception is KeyNotFoundException)
        {
            statusCode = (int)HttpStatusCode.NotFound;
            message = "The requested resource was not found.";
        }
        else if (exception is UnauthorizedAccessException)
        {
            statusCode = (int)HttpStatusCode.Unauthorized;
            message = "Authentication is required to access this resource.";
        }

        context.Response.StatusCode = statusCode;

        var errorDetails = new ErrorDetails
        {
            StatusCode = statusCode,
            Message = message,
            // Expose stack trace details only if running in Development environment
            Details = _env.IsDevelopment() ? exception.StackTrace : null
        };

        await context.Response.WriteAsync(errorDetails.ToString());
    }
}

Step 3: Register an Extension Method for Clean Setup

To keep Program.cs clean and modular, wrap the middleware registration in an extension class.

public static class MiddlewareExtensions
{
    public static IApplicationBuilder UseGlobalExceptionHandling(this IApplicationBuilder app)
    {
        return app.UseMiddleware<GlobalExceptionHandlingMiddleware>();
    }
}

Step 4: Wire Up the Middleware in Program.cs

Register your custom middleware at the very beginning of the HTTP request pipeline so it wraps all subsequent operations (such as routing, endpoint execution, and authentication).

var builder = WebApplication.CreateBuilder(args);

// Add services...
builder.Services.AddControllers();

var app = builder.Build();

// 1. Place the exception handling middleware first in the pipeline execution tree
app.UseGlobalExceptionHandling();

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

// Test endpoint designed to throw an exception on purpose
app.MapGet("/error-test", () =>
{
    throw new InvalidOperationException("Simulated catastrophic failure for middleware testing.");
});

app.Run();
Step 5: Test the Global Handler

Run your application (dotnet run) and navigate to https://localhost:{port}/error-test.

Instead of an unhandled server crash, raw HTML error dump, or dropped connection, the pipeline intercepts the InvalidOperationException and safely responds with a structured, production-ready JSON error object:

{
  "statusCode": 500,
  "message": "An internal server error has occurred.",
  "details": "   at Program.<>c.<__ hfl line>...",
  "timestamp": "2026-08-03T09:00:00Z"
}

Best ASP.NET Core 10.0 Hosting Recommendation

One of the most important things when choosing a good ASP.NET Core 8.0 hosting is the feature and reliability. HostForLIFE is the leading provider of Windows hosting and affordable ASP.NET Core, their servers are optimized for PHP web applications. The performance and the uptime of the hosting service are excellent and the features of the web hosting plan are even greater than what many hosting providers ask you to pay for. 

At HostForLIFEASP.NET, customers can also experience fast ASP.NET Core hosting. The company invested a lot of money to ensure the best and fastest performance of the datacenters, servers, network and other facilities. Its datacenters are equipped with the top equipments like cooling system, fire detection, high speed Internet connection, and so on. That is why HostForLIFEASP.NET guarantees 99.9% uptime for ASP.NET Core. And the engineers do regular maintenance and monitoring works to assure its Orchard hosting are security and always up.

0 comments:

Post a Comment