using CPRNIMS.Infrastructure.Database; using CPRNIMS.Infrastructure.Entities.Common; using CPRNIMS.WebApi.Exceptions; using System.Security.Claims; using System.Text.Json; namespace CPRNIMS.Middleware { public sealed class GlobalExceptionMiddleware { private readonly RequestDelegate _next; private readonly ILogger _logger; private readonly IWebHostEnvironment _env; private readonly IServiceScopeFactory _scopeFactory; public GlobalExceptionMiddleware( RequestDelegate next, ILogger logger, IWebHostEnvironment env, IServiceScopeFactory scopeFactory) { _next = next; _logger = logger; _env = env; _scopeFactory = scopeFactory; } public async Task InvokeAsync(HttpContext context) { try { await _next(context); } catch (Exception ex) { _logger.LogError(ex, "Unhandled exception"); await LogToDatabaseAsync(context, ex); await HandleResponseAsync(context, ex); } } private async Task LogToDatabaseAsync(HttpContext context, Exception ex) { using var scope = _scopeFactory.CreateScope(); var db = scope.ServiceProvider.GetRequiredService(); var errorLog = new ErrorLog { Id = Guid.NewGuid(), Path = context.Request.Path, HttpMethod = context.Request.Method, QueryString = context.Request.QueryString.Value, StatusCode = context.Response.StatusCode, ExceptionType = ex.GetType().FullName!, Message = ex.Message, StackTrace = ex.StackTrace, UserId = context.User?.FindFirst(ClaimTypes.NameIdentifier)?.Value, IpAddress = context.Connection.RemoteIpAddress?.ToString(), CreatedAt = DateTime.UtcNow }; db.ErrorLogs.Add(errorLog); await db.SaveChangesAsync(); } private async Task HandleResponseAsync(HttpContext context, Exception ex) { context.Response.ContentType = "application/json"; context.Response.StatusCode = ex switch { AppException app => app.StatusCode, ArgumentException => StatusCodes.Status400BadRequest, UnauthorizedAccessException => StatusCodes.Status401Unauthorized, _ => StatusCodes.Status500InternalServerError }; var response = new { success = false, message = _env.IsDevelopment() ? ex.Message : "An unexpected error occurred" }; await context.Response.WriteAsync(JsonSerializer.Serialize(response)); } } }