DEV Community

davinceleecode
davinceleecode Subscriber

Posted on

๐ŸŒ Global Error Handling in ASP.NET Core with Custom Middleware and Serilog

Error handling is a fundamental part of building reliable APIs. In this post, Iโ€™ll walk you through how to implement global error handling in ASP.NET Core using custom middleware โ€” with clean JSON error responses and Serilog for structured logging.


๐Ÿง  Why Use Global Error Handling?
Instead of wrapping every controller action in a try-catch, we can centralize error handling using middleware. This gives us:

โœ… Clean, consistent error responses
โœ… Less duplicated code
โœ… Easy error tracing with unique IDs
โœ… Integration with logging libraries like Serilog


๐Ÿ”ง Step 1: Create the Middleware Class

using System.Net;

namespace MyApp.Middlewares
{
    public class ExceptionHandlerMiddleware
    {
        private readonly ILogger<ExceptionHandlerMiddleware> _logger;
        private readonly RequestDelegate _next;

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

        public async Task InvokeAsync(HttpContext httpContext)
        {
            try
            {
                await _next(httpContext);
            }
            catch (Exception ex)
            {
                var errorId = Guid.NewGuid();

                // Log the error with a unique identifier
                _logger.LogError(ex, $"[{errorId}] Unhandled exception: {ex.Message}");

                httpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
                httpContext.Response.ContentType = "application/json";

                var error = new
                {
                    Id = errorId,
                    ErrorMessage = "Something went wrong. Please contact support with the error ID."
                };

                await httpContext.Response.WriteAsJsonAsync(error);
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

๐Ÿ“ This middleware:

  • Catches any unhandled exceptions
  • Logs them with a unique Guid
  • Returns a friendly error message in JSON format

โš™๏ธ Step 2: Register the Middleware in Program.cs
Make sure it's registered early in the request pipeline:

var app = builder.Build();

// Add our global exception handler middleware
app.UseMiddleware<ExceptionHandlerMiddleware>();

app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();

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

๐Ÿงช Step 3: Throw an Error in a Controller to Test

[HttpGet]
public IActionResult Crash()
{
    throw new Exception("Simulated crash!");
}
Enter fullscreen mode Exit fullscreen mode

Call this endpoint. You should see:

  • A clean JSON response with an error ID
  • An error logged in console/file (if Serilog is configured)

โœ๏ธ Bonus: Integrate Serilog for Logging
Add Serilog via NuGet:

dotnet add package Serilog.AspNetCore
dotnet add package Serilog.Sinks.Console
dotnet add package Serilog.Sinks.File
Enter fullscreen mode Exit fullscreen mode

Then, update your Program.cs:

using Serilog;

Log.Logger = new LoggerConfiguration()
    .MinimumLevel.Information()
    .WriteTo.Console()
    .WriteTo.File("Logs/log.txt", rollingInterval: RollingInterval.Day)
    .CreateLogger();

builder.Logging.ClearProviders();
builder.Logging.AddSerilog();
Enter fullscreen mode Exit fullscreen mode

Now all _logger.LogError() calls in your middleware (and anywhere else) will log to both the console and Logs/log.txt.


๐Ÿงผ Best Practices

  • โ— Keep your middleware early in the pipeline.
  • โœ… Always return consistent JSON error structures.
  • โž• Add contextual info like UserId, RequestPath, etc., if needed.
  • ๐Ÿ“‹ Consider logging HTTP context data (cautiously) in production.
  • ๐Ÿ’ก Use log enrichment with Serilog for deeper insights.

โœ… Final Thoughts
Global exception handling with custom middleware is a clean and scalable way to handle API errors. It improves developer experience, user experience, and observability โ€” especially when paired with Serilog.

Top comments (1)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.