Add Global Exception Handling
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
namespace Imprink.Application.Exceptions;
|
||||
|
||||
public abstract class BaseApplicationException : Exception
|
||||
{
|
||||
protected BaseApplicationException(string message) : base(message) { }
|
||||
protected BaseApplicationException(string message, Exception innerException) : base(message, innerException) { }
|
||||
}
|
||||
7
src/Imprink.Application/Exceptions/NotFoundException.cs
Normal file
7
src/Imprink.Application/Exceptions/NotFoundException.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace Imprink.Application.Exceptions;
|
||||
|
||||
public class NotFoundException : BaseApplicationException
|
||||
{
|
||||
public NotFoundException(string message) : base(message) { }
|
||||
public NotFoundException(string message, Exception innerException) : base(message, innerException) { }
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
using Imprink.Application.Exceptions;
|
||||
using Imprink.Application.Users.Dtos;
|
||||
using Imprink.Domain.Entities.Users;
|
||||
using MediatR;
|
||||
@@ -10,7 +11,8 @@ public class DeleteUserRoleHandler(IUnitOfWork uw) : IRequestHandler<DeleteUserR
|
||||
{
|
||||
public async Task<UserRoleDto?> Handle(DeleteUserRoleCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
if (!await uw.UserRepository.UserExistsAsync(request.Sub, cancellationToken)) return null;
|
||||
if (!await uw.UserRepository.UserExistsAsync(request.Sub, cancellationToken))
|
||||
throw new NotFoundException("User with ID: " + request.Sub + " does not exist.");
|
||||
|
||||
var userRole = new UserRole
|
||||
{
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Imprink.Application.Exceptions;
|
||||
using Imprink.Application.Users.Dtos;
|
||||
using MediatR;
|
||||
|
||||
@@ -9,7 +10,8 @@ public class GetUserRolesHandler(IUnitOfWork uw): IRequestHandler<GetUserRolesCo
|
||||
{
|
||||
public async Task<IEnumerable<RoleDto>> Handle(GetUserRolesCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
if (!await uw.UserRepository.UserExistsAsync(request.Sub, cancellationToken)) return [];
|
||||
if (!await uw.UserRepository.UserExistsAsync(request.Sub, cancellationToken))
|
||||
throw new NotFoundException("User with ID: " + request.Sub + " does not exist.");
|
||||
|
||||
var roles = await uw.UserRoleRepository.GetUserRolesAsync(request.Sub, cancellationToken);
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Imprink.Application.Exceptions;
|
||||
using Imprink.Application.Users.Dtos;
|
||||
using Imprink.Domain.Entities.Users;
|
||||
using MediatR;
|
||||
@@ -10,7 +11,8 @@ public class SetUserRoleHandler(IUnitOfWork uw) : IRequestHandler<SetUserRoleCom
|
||||
{
|
||||
public async Task<UserRoleDto?> Handle(SetUserRoleCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
if (!await uw.UserRepository.UserExistsAsync(request.Sub, cancellationToken)) return null;
|
||||
if (!await uw.UserRepository.UserExistsAsync(request.Sub, cancellationToken))
|
||||
throw new NotFoundException("User with ID: " + request.Sub + " does not exist.");
|
||||
|
||||
var userRole = new UserRole
|
||||
{
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Imprink.WebApi.Controllers.Users;
|
||||
public class UserRoleController(IMediator mediator) : ControllerBase
|
||||
{
|
||||
[Authorize]
|
||||
[HttpGet("/me")]
|
||||
[HttpGet("me")]
|
||||
public async Task<IActionResult> GetMyRoles()
|
||||
{
|
||||
var claims = User.Claims as Claim[] ?? User.Claims.ToArray();
|
||||
@@ -23,7 +23,7 @@ public class UserRoleController(IMediator mediator) : ControllerBase
|
||||
}
|
||||
|
||||
[Authorize(Roles = "Admin")]
|
||||
[HttpPost("/set")]
|
||||
[HttpPost("set")]
|
||||
public async Task<IActionResult> SetUserRole(SetUserRoleCommand command)
|
||||
{
|
||||
var userRole = await mediator.Send(command);
|
||||
@@ -35,7 +35,7 @@ public class UserRoleController(IMediator mediator) : ControllerBase
|
||||
}
|
||||
|
||||
[Authorize(Roles = "Admin")]
|
||||
[HttpPost("/unset")]
|
||||
[HttpPost("unset")]
|
||||
public async Task<IActionResult> UnsetUserRole(DeleteUserRoleCommand command)
|
||||
{
|
||||
var userRole = await mediator.Send(command);
|
||||
|
||||
75
src/Imprink.WebApi/Middleware/ExceptionHandlingMiddleware.cs
Normal file
75
src/Imprink.WebApi/Middleware/ExceptionHandlingMiddleware.cs
Normal file
@@ -0,0 +1,75 @@
|
||||
using System.Net;
|
||||
using System.Text.Json;
|
||||
using Imprink.Application.Exceptions;
|
||||
|
||||
namespace Imprink.WebApi.Middleware;
|
||||
|
||||
public class ExceptionHandlingMiddleware(
|
||||
RequestDelegate next,
|
||||
ILogger<ExceptionHandlingMiddleware> logger)
|
||||
{
|
||||
public async Task InvokeAsync(HttpContext context)
|
||||
{
|
||||
try
|
||||
{
|
||||
await next(context);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var (_, _, shouldLog) = GetStatusCodeAndMessage(ex);
|
||||
|
||||
if (shouldLog)
|
||||
{
|
||||
logger.LogError(ex, "An unhandled exception occurred: {Message}", ex.Message);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogInformation("Handled: {Message}", ex.Message);
|
||||
}
|
||||
|
||||
await HandleExceptionAsync(context, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task HandleExceptionAsync(HttpContext context, Exception exception)
|
||||
{
|
||||
context.Response.ContentType = "application/json";
|
||||
|
||||
var (statusCode, message, _) = GetStatusCodeAndMessage(exception);
|
||||
|
||||
context.Response.StatusCode = (int)statusCode;
|
||||
|
||||
var response = new
|
||||
{
|
||||
error = new
|
||||
{
|
||||
message,
|
||||
timestamp = DateTime.UtcNow,
|
||||
}
|
||||
};
|
||||
|
||||
var jsonResponse = JsonSerializer.Serialize(response, new JsonSerializerOptions
|
||||
{
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
|
||||
});
|
||||
|
||||
await context.Response.WriteAsync(jsonResponse);
|
||||
}
|
||||
|
||||
private static (HttpStatusCode statusCode, string message, bool shouldLog) GetStatusCodeAndMessage(Exception exception)
|
||||
{
|
||||
return exception switch
|
||||
{
|
||||
NotFoundException => (HttpStatusCode.NotFound, exception.Message, false),
|
||||
_ => (HttpStatusCode.InternalServerError, "An internal server error occurred", true)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public static class GlobalExceptionHandlingMiddlewareExtensions
|
||||
{
|
||||
public static void UseGlobalExceptionHandling(this IApplicationBuilder builder)
|
||||
{
|
||||
builder.UseMiddleware<ExceptionHandlingMiddleware>();
|
||||
}
|
||||
}
|
||||
@@ -140,13 +140,13 @@ public static class Startup
|
||||
}
|
||||
}
|
||||
|
||||
app.UseGlobalExceptionHandling();
|
||||
app.UseRequestTiming();
|
||||
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI();
|
||||
app.UseDeveloperExceptionPage();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user