using System.Net;
using System.Text.Json;
using System.ComponentModel.DataAnnotations;
namespace StoreService.Middleware;
///
/// Global error handling middleware capturing unhandled exceptions and returning structured JSON errors.
///
public class ErrorHandlingMiddleware
{
#region Fields
private readonly RequestDelegate _next;
private readonly ILogger _logger;
#endregion
#region Ctor
public ErrorHandlingMiddleware(RequestDelegate next, ILogger logger)
{
_next = next;
_logger = logger;
}
#endregion
#region Invoke
public async Task InvokeAsync(HttpContext context)
{
try
{
await _next(context);
}
catch (Exception ex)
{
await HandleExceptionAsync(context, ex);
}
}
#endregion
#region Helpers
private async Task HandleExceptionAsync(HttpContext context, Exception ex)
{
var status = ex switch
{
ValidationException => (int)HttpStatusCode.BadRequest,
ArgumentException => (int)HttpStatusCode.BadRequest,
KeyNotFoundException => (int)HttpStatusCode.NotFound,
InvalidOperationException => StatusCodes.Status409Conflict,
_ => (int)HttpStatusCode.InternalServerError
};
var errorId = Guid.NewGuid().ToString();
if (status >= 500)
{
_logger.LogError(ex, "Unhandled server exception {ErrorId}", errorId);
}
else
{
_logger.LogWarning(ex, "Handled domain exception {ErrorId} -> {Status}", errorId, status);
}
var env = context.RequestServices.GetRequiredService();
var problem = new
{
traceId = context.TraceIdentifier,
errorId,
status,
message = ex.Message,
details = env.IsDevelopment() ? ex.StackTrace : null
};
context.Response.ContentType = "application/json";
context.Response.StatusCode = status;
await context.Response.WriteAsync(JsonSerializer.Serialize(problem));
}
#endregion
}