Skip to content

Commit

Permalink
Merge pull request #66 from wemogy/feature/refit-middleware
Browse files Browse the repository at this point in the history
[BREAKING] Add Middleware for Refit Exception Filtering
  • Loading branch information
robinmanuelthiel authored Jan 18, 2024
2 parents 1cd14f8 + 8576ae0 commit b12914a
Show file tree
Hide file tree
Showing 13 changed files with 321 additions and 165 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
app.UseCloudEvents(); // when using Dapr
app.UseAuthentication();
app.UseAuthorization();
app.UseErrorHandlerMiddleware();
app.UseDefaultMiddleware(_options);
app.UseDefaultEndpoints(_options);
}
```
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using System.Collections.Generic;
using System.Net;
using System.Threading.Tasks;
using FluentAssertions;
using FluentValidation;
using FluentValidation.Results;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Wemogy.AspNet.Middlewares;
using Xunit;

namespace Wemogy.AspNet.Tests.Middlewares;

public class FluentValidationExceptionHandlerMiddlewareTests
{
[Fact]
public async Task AssertStatusCodeForFluentValidationExceptionAsync()
{
// Arrange
var context = new DefaultHttpContext
{
RequestServices = new ServiceCollection()
.AddLogging()
.BuildServiceProvider()
};
var next = new RequestDelegate(_ => throw new ValidationException(new List<ValidationFailure>()));
var middleware = new ErrorExceptionHandlerMiddleware(next);

// Act
await middleware.InvokeAsync(context);

// Assert
context.Response.StatusCode.Should().Be((int)HttpStatusCode.BadRequest);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using FluentAssertions;
using FluentValidation;
using FluentValidation.Results;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Wemogy.AspNet.Middlewares;
using Wemogy.Core.Errors.Exceptions;
using Xunit;

namespace Wemogy.AspNet.Tests.Middlewares;

public class ErrorExceptionHandlerMiddlewareTests
{
[Theory]
[InlineData(typeof(AuthorizationErrorException), HttpStatusCode.Forbidden)]
[InlineData(typeof(ConflictErrorException), HttpStatusCode.Conflict)]
[InlineData(typeof(FailureErrorException), HttpStatusCode.BadRequest)]
[InlineData(typeof(NotFoundErrorException), HttpStatusCode.NotFound)]
[InlineData(typeof(PreconditionFailedErrorException), HttpStatusCode.PreconditionFailed)]
[InlineData(typeof(UnexpectedErrorException), HttpStatusCode.InternalServerError)]
[InlineData(typeof(ValidationErrorException), HttpStatusCode.BadRequest)]
public async Task AssertStatusCodeForErrorAsync(Type errorExceptionType, HttpStatusCode expectedHttpStatusCode)
{
// Arrange
if (Activator.CreateInstance(errorExceptionType, "Test", "Test description", null) is not ErrorException errorException)
{
throw new Exception($"The type {errorExceptionType} is not a valid ErrorException");
}

var context = new DefaultHttpContext
{
RequestServices = new ServiceCollection()
.AddLogging()
.BuildServiceProvider()
};
var next = new RequestDelegate(_ => throw errorException);
var middleware = new ErrorExceptionHandlerMiddleware(next);

// Act
await middleware.InvokeAsync(context);

// Assert
context.Response.StatusCode.Should().Be((int)expectedHttpStatusCode);
}
}
117 changes: 0 additions & 117 deletions src/Wemogy.AspNet.Tests/Middlewares/ErrorHandlerMiddlewareTests.cs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using FluentAssertions;
using FluentValidation;
using FluentValidation.Results;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Wemogy.AspNet.Middlewares;
using Wemogy.Core.Errors.Exceptions;
using Xunit;

namespace Wemogy.AspNet.Tests.Middlewares;

public class SystemExceptionHandlerMiddleware
{
[Fact]
public async Task CanceledRequestShouldBeIgnored()
{
// Arrange
var abortedCts = new CancellationTokenSource();
var context = new DefaultHttpContext
{
RequestServices = new ServiceCollection()
.AddLogging()
.BuildServiceProvider(),
RequestAborted = abortedCts.Token
};
var next = new RequestDelegate(
c =>
{
// simulate that somewhere in the pipeline we are checking for cancellation
c.RequestAborted.ThrowIfCancellationRequested();
return Task.CompletedTask;
});
var middleware = new ErrorExceptionHandlerMiddleware(next);

// Act
abortedCts.Cancel(); // simulate that the request was aborted
var exception = await Record.ExceptionAsync(() => middleware.InvokeAsync(context));

// Assert
exception.Should().BeNull();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using System.IO;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using FluentAssertions;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Refit;
using Wemogy.AspNet.Refit;
using Xunit;

namespace Wemogy.AspNet.Tests.Middlewares;

public class RefitExceptionHandlerMiddlewareTests
{
[Theory]
[InlineData(HttpStatusCode.NotFound)]
public async Task AssertStatusCodeForErrorAsync(HttpStatusCode expectedHttpStatusCode)
{
// Arrange
var context = new DefaultHttpContext
{
RequestServices = new ServiceCollection()
.AddLogging()
.BuildServiceProvider()
};
var message = new HttpRequestMessage(HttpMethod.Get, "http://localhost");
var response = new HttpResponseMessage(expectedHttpStatusCode)
{
Content = new StringContent("Bar")
};
var apiException = await ApiException.Create(message, HttpMethod.Get, response, new RefitSettings());
var next = new RequestDelegate(_ => throw apiException);
var middleware = new RefitExceptionHandlerMiddleware(next);

// Act
await middleware.InvokeAsync(context);

// Assert
context.Response.StatusCode.Should().Be((int)expectedHttpStatusCode);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using System;
using System.Net;
using System.Threading.Tasks;
using FluentValidation;
using Microsoft.AspNetCore.Http;

namespace Wemogy.AspNet.FluentValidation
{
public class FluentValidationExceptionHandlerMiddleware
{
private readonly RequestDelegate _next;

public FluentValidationExceptionHandlerMiddleware(RequestDelegate next)
{
_next = next;
}

public async Task InvokeAsync(HttpContext context)
{
try
{
await _next(context);
}
catch (ValidationException exception)
{
var response = context.Response;
response.StatusCode = (int)HttpStatusCode.BadRequest;
await response.WriteAsJsonAsync(exception.Errors);
}

// Catch OperationCanceledException, when the request is aborted
catch (OperationCanceledException)
{
if (context.RequestAborted.IsCancellationRequested)
{
return;
}

throw;
}
}
}
}
12 changes: 0 additions & 12 deletions src/Wemogy.AspNet/Middlewares/DependencyInjection.cs

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@

namespace Wemogy.AspNet.Middlewares
{
public class ErrorHandlerMiddleware
public class ErrorExceptionHandlerMiddleware
{
private readonly RequestDelegate _next;

public ErrorHandlerMiddleware(RequestDelegate next)
public ErrorExceptionHandlerMiddleware(RequestDelegate next)
{
_next = next;
}
Expand Down
Loading

0 comments on commit b12914a

Please sign in to comment.