diff --git a/src/Infrastructure.Tests/FilterTests.cs b/src/Infrastructure.Tests/FilterTests.cs new file mode 100644 index 0000000..537a329 --- /dev/null +++ b/src/Infrastructure.Tests/FilterTests.cs @@ -0,0 +1,60 @@ +using Infrastructure.Exceptions; +using Infrastructure.Filters; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Controllers; +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.AspNetCore.Routing; +using Microsoft.Extensions.Logging; +using Moq; + +namespace Infrastructure.Tests; + +public class FilterTests +{ + private readonly ActionContext _actionContext = new ActionContext + { + HttpContext = new DefaultHttpContext(), + RouteData = new RouteData(), + ActionDescriptor = new ControllerActionDescriptor(), + }; + [Fact] + public async Task OnExceptionAsync_HandlesGenericException() + { + // Arrange + var loggerMock = new Mock>(); + var filter = new ExceptionsFilter(loggerMock.Object); + + var exceptionContext = new ExceptionContext(_actionContext, new List()) + { + Exception = new Exception("Generic error") + }; + // Act + await filter.OnExceptionAsync(exceptionContext); + var contentResult = Assert.IsType(exceptionContext.Result); + Assert.Equal(StatusCodes.Status200OK, contentResult.StatusCode); + Assert.Equal("application/json;charset=utf-8", contentResult.ContentType); + Assert.Contains("Generic error", contentResult.Content); + } + + + [Fact] + public async Task OnExceptionAsync_HandlesFriendException() + { + // Arrange + var loggerMock = new Mock>(); + var filter = new ExceptionsFilter(loggerMock.Object); + + var exceptionContext = new ExceptionContext(_actionContext, new List()) + { + Exception = new FriendlyException("Friendly error") + }; + // Act + await filter.OnExceptionAsync(exceptionContext); + var contentResult = Assert.IsType(exceptionContext.Result); + Assert.Equal(StatusCodes.Status200OK, contentResult.StatusCode); + Assert.Equal("application/json;charset=utf-8", contentResult.ContentType); + Assert.Contains("Friendly error", contentResult.Content); + Assert.Contains("500", contentResult.Content); + } +} \ No newline at end of file diff --git a/src/Infrastructure.Tests/Infrastructure.Tests.csproj b/src/Infrastructure.Tests/Infrastructure.Tests.csproj index 7aae03d..48ec50e 100644 --- a/src/Infrastructure.Tests/Infrastructure.Tests.csproj +++ b/src/Infrastructure.Tests/Infrastructure.Tests.csproj @@ -16,6 +16,7 @@ + all diff --git a/src/Infrastructure/Exceptions/FriendlyException.cs b/src/Infrastructure/Exceptions/FriendlyException.cs new file mode 100644 index 0000000..bd33cfe --- /dev/null +++ b/src/Infrastructure/Exceptions/FriendlyException.cs @@ -0,0 +1,13 @@ +namespace Infrastructure.Exceptions; + +public sealed class FriendlyException(string message, int code = 500) : Exception +{ + public string? Message { get; set; } = message; + + public int Code { get; set; } = code; + + public MessageData ConvertToMessage() + { + return new MessageData(false, Message, Code); + } +} \ No newline at end of file diff --git a/src/Infrastructure/Filters/ExceptionsFilter.cs b/src/Infrastructure/Filters/ExceptionsFilter.cs new file mode 100644 index 0000000..8fd788a --- /dev/null +++ b/src/Infrastructure/Filters/ExceptionsFilter.cs @@ -0,0 +1,38 @@ +using Infrastructure.Exceptions; +using Infrastructure.Utils; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Filters; +using Microsoft.Extensions.Logging; + +namespace Infrastructure.Filters; + +public class ExceptionsFilter(ILogger logger) : IAsyncExceptionFilter +{ + public Task OnExceptionAsync(ExceptionContext context) + { + if (context.ExceptionHandled) + { + return Task.CompletedTask; + } + var message = default(MessageData); + if (context.Exception is FriendlyException fe) + { + message = fe.ConvertToMessage(); + } + else + { + logger.LogError(context.Exception.Message); + message = new MessageData(false, context.Exception.Message); + } + + context.Result = new ContentResult + { + StatusCode = StatusCodes.Status200OK, + ContentType = "application/json;charset=utf-8", + Content = message.Serialize() + }; + context.ExceptionHandled = true; + return Task.CompletedTask; + } +} \ No newline at end of file