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);