using System.Text.Json; using public_valetax.Exceptions; using public_valetax.Repositories; namespace public_valetax.Middleware { public class ExceptionHandlingMiddleware(RequestDelegate _next, ILogger _logger) { public async Task InvokeAsync(HttpContext context, IJournalRepository journalRepository) { try { if (context.Request.ContentLength > 0) { context.Request.EnableBuffering(); } await _next(context); } catch (Exception ex) { _logger.LogError(ex, "An unhandled exception occurred"); // Generate event ID var eventId = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); // Capture request details var queryParameters = context.Request.QueryString.ToString(); string? bodyParameters = null; // Try to capture body parameters (be careful not to consume the stream multiple times) if (context.Request.ContentLength > 0) { context.Request.Body.Position = 0; // Reset for next middleware using var reader = new StreamReader(context.Request.Body, leaveOpen: true); bodyParameters = await reader.ReadToEndAsync(); context.Request.Body.Position = 0; // Reset for next middleware } // Log to journal await journalRepository.CreateJournalEntryAsync( eventId, ex.GetType().Name, ex.Message, queryParameters, bodyParameters, ex.StackTrace); // Handle specific exception types await HandleExceptionAsync(context, ex, eventId); } } private static async Task HandleExceptionAsync(HttpContext context, Exception exception, long eventId) { var response = new { type = exception is SecureException ? "Secure" : "Exception", id = eventId.ToString(), data = new { message = exception is SecureException ? exception.Message : $"Internal server error ID = {eventId}" } }; context.Response.ContentType = "application/json"; context.Response.StatusCode = StatusCodes.Status500InternalServerError; var jsonResponse = JsonSerializer.Serialize(response); await context.Response.WriteAsync(jsonResponse); } } }