From ec394a9b613b28df08b4c8bd7d475cc4326b1a1c Mon Sep 17 00:00:00 2001 From: prtsie Date: Sun, 18 Aug 2024 19:53:40 +0300 Subject: [PATCH] Exceptions handling --- .../EditLocationsRequestsHandler.cs | 2 +- ...tipleIdenticalCitiesInCountryException.cs} | 2 +- .../EntityNotFoundByIdException.cs | 4 +- .../SchengenVisaApi/DependencyInjection.cs | 5 +- .../GlobalExceptionsFilter.cs | 63 +++++++++++++++++++ .../SchengenVisaApi/RequestPipeline.cs | 2 + 6 files changed, 73 insertions(+), 5 deletions(-) rename SchengenVisaApi/ApplicationLayer/DataAccessingServices/Locations/RequestHandlers/AdminRequests/Exceptions/{MultipleIdenticalCitiesInCountry.cs => MultipleIdenticalCitiesInCountryException.cs} (52%) create mode 100644 SchengenVisaApi/SchengenVisaApi/ExceptionFilters/GlobalExceptionsFilter.cs diff --git a/SchengenVisaApi/ApplicationLayer/DataAccessingServices/Locations/RequestHandlers/AdminRequests/EditLocationsRequestsHandler.cs b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/Locations/RequestHandlers/AdminRequests/EditLocationsRequestsHandler.cs index e84e975..b02c308 100644 --- a/SchengenVisaApi/ApplicationLayer/DataAccessingServices/Locations/RequestHandlers/AdminRequests/EditLocationsRequestsHandler.cs +++ b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/Locations/RequestHandlers/AdminRequests/EditLocationsRequestsHandler.cs @@ -18,7 +18,7 @@ namespace ApplicationLayer.DataAccessingServices.Locations.RequestHandlers.Admin if (request.Cities.Distinct().Count() < request.Cities.Length) { - throw new MultipleIdenticalCitiesInCountry(); + throw new MultipleIdenticalCitiesInCountryException(); } var country = new Country diff --git a/SchengenVisaApi/ApplicationLayer/DataAccessingServices/Locations/RequestHandlers/AdminRequests/Exceptions/MultipleIdenticalCitiesInCountry.cs b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/Locations/RequestHandlers/AdminRequests/Exceptions/MultipleIdenticalCitiesInCountryException.cs similarity index 52% rename from SchengenVisaApi/ApplicationLayer/DataAccessingServices/Locations/RequestHandlers/AdminRequests/Exceptions/MultipleIdenticalCitiesInCountry.cs rename to SchengenVisaApi/ApplicationLayer/DataAccessingServices/Locations/RequestHandlers/AdminRequests/Exceptions/MultipleIdenticalCitiesInCountryException.cs index a32da0a..9716ac2 100644 --- a/SchengenVisaApi/ApplicationLayer/DataAccessingServices/Locations/RequestHandlers/AdminRequests/Exceptions/MultipleIdenticalCitiesInCountry.cs +++ b/SchengenVisaApi/ApplicationLayer/DataAccessingServices/Locations/RequestHandlers/AdminRequests/Exceptions/MultipleIdenticalCitiesInCountryException.cs @@ -2,5 +2,5 @@ namespace ApplicationLayer.DataAccessingServices.Locations.RequestHandlers.AdminRequests.Exceptions { - public class MultipleIdenticalCitiesInCountry() : ApiException("There are multiple cities with one name in the country."); + public class MultipleIdenticalCitiesInCountryException() : ApiException("There are multiple cities with one name in the country."); } diff --git a/SchengenVisaApi/Infrastructure/Database/GeneralExceptions/EntityNotFoundByIdException.cs b/SchengenVisaApi/Infrastructure/Database/GeneralExceptions/EntityNotFoundByIdException.cs index 727fc95..d7637aa 100644 --- a/SchengenVisaApi/Infrastructure/Database/GeneralExceptions/EntityNotFoundByIdException.cs +++ b/SchengenVisaApi/Infrastructure/Database/GeneralExceptions/EntityNotFoundByIdException.cs @@ -5,5 +5,5 @@ namespace Infrastructure.Database.GeneralExceptions; /// Exception to throw when entity not found /// Identifier of entity /// Type of entity -public class EntityNotFoundByIdException(Guid id) : EntityNotFoundException($"Entity {typeof(T).Name} with id {id} not found.") - where T : class, IEntity; \ No newline at end of file +public class EntityNotFoundByIdException(Guid id) : EntityNotFoundException($"{typeof(T).Name} with id {id} not found.") + where T : class, IEntity; diff --git a/SchengenVisaApi/SchengenVisaApi/DependencyInjection.cs b/SchengenVisaApi/SchengenVisaApi/DependencyInjection.cs index f1e759b..90693bb 100644 --- a/SchengenVisaApi/SchengenVisaApi/DependencyInjection.cs +++ b/SchengenVisaApi/SchengenVisaApi/DependencyInjection.cs @@ -10,6 +10,7 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; using SchengenVisaApi.Common; +using SchengenVisaApi.ExceptionFilters; using Swashbuckle.AspNetCore.SwaggerGen; namespace SchengenVisaApi; @@ -39,7 +40,9 @@ public static class DependencyInjection services.AddSwagger(); } - services.AddControllers(); + services.AddProblemDetails(); + + services.AddControllers(opts => opts.Filters.Add()); } /// Adds authentication, authorization and token generator diff --git a/SchengenVisaApi/SchengenVisaApi/ExceptionFilters/GlobalExceptionsFilter.cs b/SchengenVisaApi/SchengenVisaApi/ExceptionFilters/GlobalExceptionsFilter.cs new file mode 100644 index 0000000..7e62f64 --- /dev/null +++ b/SchengenVisaApi/SchengenVisaApi/ExceptionFilters/GlobalExceptionsFilter.cs @@ -0,0 +1,63 @@ +using ApplicationLayer.DataAccessingServices.AuthServices.LoginService.Exceptions; +using ApplicationLayer.DataAccessingServices.Locations.RequestHandlers.AdminRequests.Exceptions; +using ApplicationLayer.GeneralExceptions; +using Domains; +using Infrastructure.Database.GeneralExceptions; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; + +namespace SchengenVisaApi.ExceptionFilters +{ + /// Handles + public class GlobalExceptionsFilter : IAsyncExceptionFilter + { + /// + public async Task OnExceptionAsync(ExceptionContext context) + { + var exception = context.Exception; + var problemDetails = new ProblemDetails(); + + if (exception is ApiException) + { + problemDetails.Detail = exception.Message; + switch (exception) + { + case EntityNotFoundException: + problemDetails.Status = StatusCodes.Status404NotFound; + problemDetails.Title = "Requested entity not found"; + problemDetails.Type = "https://datatracker.ietf.org/doc/html/rfc7231#section-6.5.4"; + break; + case IncorrectLoginDataException: + problemDetails.Status = StatusCodes.Status403Forbidden; + problemDetails.Title = "Auth failed"; + problemDetails.Type = "https://datatracker.ietf.org/doc/html/rfc7231#section-6.5.3"; + break; + case AlreadyExistsException: + problemDetails.Status = StatusCodes.Status409Conflict; + problemDetails.Title = "Already exists"; + problemDetails.Type = "https://datatracker.ietf.org/doc/html/rfc7231#section-6.5.8"; + break; + case MultipleIdenticalCitiesInCountryException: + problemDetails.Status = StatusCodes.Status400BadRequest; + problemDetails.Title = "Can not add cities with one name to one country"; + problemDetails.Type = "https://datatracker.ietf.org/doc/html/rfc7231#section-6.5.1"; + break; + default: + problemDetails.Status = StatusCodes.Status400BadRequest; + problemDetails.Title = "Bad request"; + problemDetails.Type = "https://datatracker.ietf.org/doc/html/rfc7231#section-6.5.1"; + break; + } + } + else + { + problemDetails.Status = StatusCodes.Status500InternalServerError; + problemDetails.Title = "An unhandled error occured"; + problemDetails.Type = "https://datatracker.ietf.org/doc/html/rfc7231#section-6.6.1"; + } + + await Results.Problem(problemDetails).ExecuteAsync(context.HttpContext); + context.ExceptionHandled = true; + } + } +} diff --git a/SchengenVisaApi/SchengenVisaApi/RequestPipeline.cs b/SchengenVisaApi/SchengenVisaApi/RequestPipeline.cs index 2e5c653..6846a9f 100644 --- a/SchengenVisaApi/SchengenVisaApi/RequestPipeline.cs +++ b/SchengenVisaApi/SchengenVisaApi/RequestPipeline.cs @@ -11,6 +11,8 @@ public static class PipelineRequest app.UseHttpsRedirection(); + app.UseStatusCodePages(); + app.UseAuthentication() .UseAuthorization();