Add exception handling middleware

Implement global exception handling to provide consistent error responses.
Registes custom exceptions with corresponding HTTP status codes and descriptions.
This commit is contained in:
martinshoob 2025-08-11 18:36:12 +02:00
parent 1906d0de0d
commit 7bf7f23925
3 changed files with 16 additions and 7 deletions

View file

@ -19,6 +19,7 @@ public class UserProfileController : ControllerBase
_userProfileService = userProfileService; _userProfileService = userProfileService;
} }
[HttpPut]
public UserProfileGet PutUserProfile([FromBody] UserProfilePut userProfile) public UserProfileGet PutUserProfile([FromBody] UserProfilePut userProfile)
{ {
throw new ApplicationException(); throw new ApplicationException();

View file

@ -1,8 +1,9 @@
using System.Net; using System.Net;
using Microsoft.AspNetCore.Http.HttpResults;
namespace DrinkRateAPI.Exceptions; namespace DrinkRateAPI.Exceptions;
public record ExceptionResponse(HttpStatusCode StatusCode, string Description); public record ExceptionResponse(int StatusCode, string Description);
public class ExceptionHandlingMiddleware public class ExceptionHandlingMiddleware
{ {
@ -32,16 +33,20 @@ public class ExceptionHandlingMiddleware
_logger.LogError(exception, "An unexpected error occurred."); _logger.LogError(exception, "An unexpected error occurred.");
ExceptionResponse response = exception switch var response = exception switch
{ {
ApplicationException _ => new ExceptionResponse(HttpStatusCode.BadRequest, "Application exception occurred."), BadRequestException _ => new ExceptionResponse(StatusCodes.Status400BadRequest, "Application exception occurred."),
KeyNotFoundException _ => new ExceptionResponse(HttpStatusCode.NotFound, "The request key not found."), NotFoundException _ => new ExceptionResponse(StatusCodes.Status404NotFound, "The request key not found."),
UnauthorizedAccessException _ => new ExceptionResponse(HttpStatusCode.Unauthorized, "Unauthorized."), UnauthenticatedException _ => new ExceptionResponse(StatusCodes.Status401Unauthorized, "Unauthorized."),
_ => new ExceptionResponse(HttpStatusCode.InternalServerError, "Internal server error. Please retry later.") PaymentRequiredException _ => new ExceptionResponse(StatusCodes.Status402PaymentRequired, "Payment required."),
ForbiddenException _ => new ExceptionResponse(StatusCodes.Status403Forbidden, "Forbidden."),
IamATeapotException _ => new ExceptionResponse(StatusCodes.Status418ImATeapot, "I am a teapot."),
UnavailableForLagalReasonsException _ => new ExceptionResponse(StatusCodes.Status451UnavailableForLegalReasons, "Unavailable for legal reasons."),
_ => new ExceptionResponse(StatusCodes.Status500InternalServerError, "Internal server error. Please retry later.")
}; };
context.Response.ContentType = "application/json"; context.Response.ContentType = "application/json";
context.Response.StatusCode = (int)response.StatusCode; context.Response.StatusCode = response.StatusCode;
await context.Response.WriteAsJsonAsync(response); await context.Response.WriteAsJsonAsync(response);
} }
} }

View file

@ -1,6 +1,7 @@
using DrinkRateAPI.AuthorizationPolicies; using DrinkRateAPI.AuthorizationPolicies;
using DrinkRateAPI.Contexts; using DrinkRateAPI.Contexts;
using DrinkRateAPI.DbEntities; using DrinkRateAPI.DbEntities;
using DrinkRateAPI.Exceptions;
using DrinkRateAPI.Services; using DrinkRateAPI.Services;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity;
@ -70,6 +71,8 @@ if (app.Environment.IsDevelopment())
app.MapIdentityApi<DbApplicationUser>(); app.MapIdentityApi<DbApplicationUser>();
app.UseMiddleware<ExceptionHandlingMiddleware>();
app.UseHttpsRedirection(); app.UseHttpsRedirection();
app.UseAuthorization(); app.UseAuthorization();