From e41338eda2bda31b30f276df360dc9ae481f1239 Mon Sep 17 00:00:00 2001 From: Stevan Freeborn <65925598+StevanFreeborn@users.noreply.github.com> Date: Sun, 4 Jan 2026 22:08:05 -0600 Subject: [PATCH] feat(logging): implement GlobalExceptionHandler for centralized error handling --- .../Logging/GlobalExceptionHandler.cs | 31 +++++++++++++++++++ src/GroundsForSupport.Server/Program.cs | 4 +++ 2 files changed, 35 insertions(+) create mode 100644 src/GroundsForSupport.Server/Logging/GlobalExceptionHandler.cs diff --git a/src/GroundsForSupport.Server/Logging/GlobalExceptionHandler.cs b/src/GroundsForSupport.Server/Logging/GlobalExceptionHandler.cs new file mode 100644 index 0000000..5a4fc0c --- /dev/null +++ b/src/GroundsForSupport.Server/Logging/GlobalExceptionHandler.cs @@ -0,0 +1,31 @@ +using Microsoft.AspNetCore.Diagnostics; +using Microsoft.AspNetCore.Mvc; + +namespace GroundsForSupport.Server.Logging; + +internal sealed class GlobalExceptionHandler(ILogger logger) : IExceptionHandler +{ + private readonly ILogger _logger = logger; + + public async ValueTask TryHandleAsync( + HttpContext httpContext, + Exception exception, + CancellationToken cancellationToken + ) + { + _logger.LogError(exception, "Exception occurred: {Message}", exception.Message); + + var problemDetails = new ProblemDetails + { + Status = StatusCodes.Status500InternalServerError, + Title = "Server Error", + Detail = "An internal error occurred." + }; + + httpContext.Response.StatusCode = problemDetails.Status.Value; + + await httpContext.Response.WriteAsJsonAsync(problemDetails, cancellationToken); + + return true; + } +} \ No newline at end of file diff --git a/src/GroundsForSupport.Server/Program.cs b/src/GroundsForSupport.Server/Program.cs index d76b978..4bd333b 100644 --- a/src/GroundsForSupport.Server/Program.cs +++ b/src/GroundsForSupport.Server/Program.cs @@ -1,6 +1,7 @@ using System.Text.Json; using GroundsForSupport.Server.Data; +using GroundsForSupport.Server.Logging; using GroundsForSupport.Server.Payments.Endpoints; using GroundsForSupport.Server.Payments.Stripe; using GroundsForSupport.Server.RateLimiting; @@ -13,6 +14,7 @@ builder.Services.AddOpenApi(); builder.Services.AddValidation(); +builder.Services.AddExceptionHandler(); builder.Services.AddProblemDetails(); builder.Services.AddHttpClient(); @@ -38,6 +40,8 @@ builder.Services.ConfigureHttpJsonOptions( var app = builder.Build(); +app.UseExceptionHandler(); + if (app.Environment.IsDevelopment()) { app.MapOpenApi();