diff --git a/EnvelopeGenerator.GeneratorAPI/Middleware/ExceptionHandlingMiddleware.cs b/EnvelopeGenerator.GeneratorAPI/Middleware/ExceptionHandlingMiddleware.cs new file mode 100644 index 00000000..2ac95f3e --- /dev/null +++ b/EnvelopeGenerator.GeneratorAPI/Middleware/ExceptionHandlingMiddleware.cs @@ -0,0 +1,90 @@ +namespace EnvelopeGenerator.GeneratorAPI.Middleware; + +using EnvelopeGenerator.Application.Exceptions; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; +using System.Net; +using System.Text.Json; + +/// +/// Middleware for handling exceptions globally in the application. +/// Captures exceptions thrown during the request pipeline execution, +/// logs them, and returns an appropriate HTTP response with a JSON error message. +/// +public class ExceptionHandlingMiddleware +{ + private readonly RequestDelegate _next; + private readonly ILogger _logger; + + /// + /// Initializes a new instance of the class. + /// + /// The next middleware in the request pipeline. + /// The logger instance for logging exceptions. + public ExceptionHandlingMiddleware(RequestDelegate next, ILogger logger) + { + _next = next; + _logger = logger; + } + + /// + /// Invokes the middleware to handle the HTTP request. + /// + /// The HTTP context of the current request. + /// A task that represents the asynchronous operation. + public async Task InvokeAsync(HttpContext context) + { + try + { + await _next(context); // Continue down the pipeline + } + catch (Exception ex) + { + await HandleExceptionAsync(context, ex, _logger); + } + } + + /// + /// Handles exceptions by logging them and writing an appropriate JSON response. + /// + /// The HTTP context of the current request. + /// The exception that occurred. + /// The logger instance for logging the exception. + /// A task that represents the asynchronous operation. + private static async Task HandleExceptionAsync(HttpContext context, Exception exception, ILogger logger) + { + context.Response.ContentType = "application/json"; + var response = context.Response; + + string message; + int statusCode; + + switch (exception) + { + case BadRequestException badRequestEx: + statusCode = (int)HttpStatusCode.BadRequest; + message = badRequestEx.Message; + break; + + case NotFoundException notFoundEx: + statusCode = (int)HttpStatusCode.NotFound; + message = notFoundEx.Message; + break; + + default: + logger.LogError(exception, "Unhandled exception occurred."); + statusCode = (int)HttpStatusCode.InternalServerError; + message = "An unexpected error occurred."; + break; + } + + response.StatusCode = statusCode; + + var result = JsonSerializer.Serialize(new + { + error = message + }); + + await context.Response.WriteAsync(result); + } +} diff --git a/EnvelopeGenerator.GeneratorAPI/Program.cs b/EnvelopeGenerator.GeneratorAPI/Program.cs index 4c09198f..b41d4b62 100644 --- a/EnvelopeGenerator.GeneratorAPI/Program.cs +++ b/EnvelopeGenerator.GeneratorAPI/Program.cs @@ -15,6 +15,7 @@ using EnvelopeGenerator.GeneratorAPI.Models; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.IdentityModel.Tokens; using DigitalData.Core.Abstractions.Security.Extensions; +using EnvelopeGenerator.GeneratorAPI.Middleware; var builder = WebApplication.CreateBuilder(args); @@ -169,6 +170,8 @@ var app = builder.Build(); deferredProvider.Factory = () => app.Services; +app.UseMiddleware(); + app.MapOpenApi(); // Configure the HTTP request pipeline.