From 289dba9b16ab179f5ab480ef3dd858e1470b8498 Mon Sep 17 00:00:00 2001 From: OlgunR Date: Mon, 19 Jan 2026 08:31:10 +0100 Subject: [PATCH] Add global exception handling middleware to API Introduced ExceptionHandlingMiddleware to catch and log unhandled exceptions, returning standardized JSON error responses. Registered the middleware in the request pipeline. Also made minor formatting and comment improvements in Program.cs and ICatalogRepository.cs. --- .../Middleware/ExceptionHandlingMiddleware.cs | 52 +++++++++++++++++++ DbFirst.API/Program.cs | 5 +- .../Repositories/ICatalogRepository.cs | 2 +- 3 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 DbFirst.API/Middleware/ExceptionHandlingMiddleware.cs diff --git a/DbFirst.API/Middleware/ExceptionHandlingMiddleware.cs b/DbFirst.API/Middleware/ExceptionHandlingMiddleware.cs new file mode 100644 index 0000000..4957a94 --- /dev/null +++ b/DbFirst.API/Middleware/ExceptionHandlingMiddleware.cs @@ -0,0 +1,52 @@ +using System.Net; +using System.Text.Json; + +namespace DbFirst.API.Middleware; + +public class ExceptionHandlingMiddleware +{ + private readonly RequestDelegate _next; + private readonly ILogger _logger; + + public ExceptionHandlingMiddleware(RequestDelegate next, ILogger logger) + { + _next = next; + _logger = logger; + } + + public async Task InvokeAsync(HttpContext context) + { + try + { + await _next(context); + } + catch (Exception ex) + { + _logger.LogError(ex, "Unhandled exception"); + await WriteProblemDetailsAsync(context, ex); + } + } + + private static async Task WriteProblemDetailsAsync(HttpContext context, Exception ex) + { + if (context.Response.HasStarted) + { + throw ex; + } + + context.Response.Clear(); + context.Response.StatusCode = (int)HttpStatusCode.InternalServerError; + context.Response.ContentType = "application/json"; + + var problem = new + { + type = "https://tools.ietf.org/html/rfc9110#section-15.6.1", + title = "Serverfehler", + status = context.Response.StatusCode, + detail = ex.Message, + traceId = context.TraceIdentifier + }; + + await context.Response.WriteAsync(JsonSerializer.Serialize(problem)); + } +} diff --git a/DbFirst.API/Program.cs b/DbFirst.API/Program.cs index 07ce535..c9b5a30 100644 --- a/DbFirst.API/Program.cs +++ b/DbFirst.API/Program.cs @@ -3,8 +3,9 @@ using DbFirst.Domain.Repositories; using DbFirst.Infrastructure; using DbFirst.Infrastructure.Repositories; using Microsoft.EntityFrameworkCore; +using DbFirst.API.Middleware; -//TODO: create and add exception handling middleware +// TODO: create and add exception handling middleware - Done var builder = WebApplication.CreateBuilder(args); @@ -43,6 +44,8 @@ if (app.Environment.IsDevelopment()) app.UseSwaggerUI(); } +app.UseMiddleware(); + app.UseHttpsRedirection(); app.UseCors(); app.UseAuthorization(); diff --git a/DbFirst.Domain/Repositories/ICatalogRepository.cs b/DbFirst.Domain/Repositories/ICatalogRepository.cs index 85b1acd..f968a01 100644 --- a/DbFirst.Domain/Repositories/ICatalogRepository.cs +++ b/DbFirst.Domain/Repositories/ICatalogRepository.cs @@ -3,7 +3,7 @@ using DbFirst.Domain.Entities; namespace DbFirst.Domain.Repositories; // TODO: instead of creating interface per entity, consider using generic repository pattern (eg. IRepository) to reduce code duplication. -//TODO: move to application layer as a part of clean architecture +// TODO: move to application layer as a part of clean architecture public interface ICatalogRepository { Task> GetAllAsync(CancellationToken cancellationToken = default);