Skip to content

Commit b12914a

Browse files
Merge pull request #66 from wemogy/feature/refit-middleware
[BREAKING] Add Middleware for Refit Exception Filtering
2 parents 1cd14f8 + 8576ae0 commit b12914a

13 files changed

+321
-165
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
8181
app.UseCloudEvents(); // when using Dapr
8282
app.UseAuthentication();
8383
app.UseAuthorization();
84-
app.UseErrorHandlerMiddleware();
84+
app.UseDefaultMiddleware(_options);
8585
app.UseDefaultEndpoints(_options);
8686
}
8787
```
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using System.Collections.Generic;
2+
using System.Net;
3+
using System.Threading.Tasks;
4+
using FluentAssertions;
5+
using FluentValidation;
6+
using FluentValidation.Results;
7+
using Microsoft.AspNetCore.Http;
8+
using Microsoft.Extensions.DependencyInjection;
9+
using Wemogy.AspNet.Middlewares;
10+
using Xunit;
11+
12+
namespace Wemogy.AspNet.Tests.Middlewares;
13+
14+
public class FluentValidationExceptionHandlerMiddlewareTests
15+
{
16+
[Fact]
17+
public async Task AssertStatusCodeForFluentValidationExceptionAsync()
18+
{
19+
// Arrange
20+
var context = new DefaultHttpContext
21+
{
22+
RequestServices = new ServiceCollection()
23+
.AddLogging()
24+
.BuildServiceProvider()
25+
};
26+
var next = new RequestDelegate(_ => throw new ValidationException(new List<ValidationFailure>()));
27+
var middleware = new ErrorExceptionHandlerMiddleware(next);
28+
29+
// Act
30+
await middleware.InvokeAsync(context);
31+
32+
// Assert
33+
context.Response.StatusCode.Should().Be((int)HttpStatusCode.BadRequest);
34+
}
35+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Net;
4+
using System.Threading;
5+
using System.Threading.Tasks;
6+
using FluentAssertions;
7+
using FluentValidation;
8+
using FluentValidation.Results;
9+
using Microsoft.AspNetCore.Http;
10+
using Microsoft.Extensions.DependencyInjection;
11+
using Wemogy.AspNet.Middlewares;
12+
using Wemogy.Core.Errors.Exceptions;
13+
using Xunit;
14+
15+
namespace Wemogy.AspNet.Tests.Middlewares;
16+
17+
public class ErrorExceptionHandlerMiddlewareTests
18+
{
19+
[Theory]
20+
[InlineData(typeof(AuthorizationErrorException), HttpStatusCode.Forbidden)]
21+
[InlineData(typeof(ConflictErrorException), HttpStatusCode.Conflict)]
22+
[InlineData(typeof(FailureErrorException), HttpStatusCode.BadRequest)]
23+
[InlineData(typeof(NotFoundErrorException), HttpStatusCode.NotFound)]
24+
[InlineData(typeof(PreconditionFailedErrorException), HttpStatusCode.PreconditionFailed)]
25+
[InlineData(typeof(UnexpectedErrorException), HttpStatusCode.InternalServerError)]
26+
[InlineData(typeof(ValidationErrorException), HttpStatusCode.BadRequest)]
27+
public async Task AssertStatusCodeForErrorAsync(Type errorExceptionType, HttpStatusCode expectedHttpStatusCode)
28+
{
29+
// Arrange
30+
if (Activator.CreateInstance(errorExceptionType, "Test", "Test description", null) is not ErrorException errorException)
31+
{
32+
throw new Exception($"The type {errorExceptionType} is not a valid ErrorException");
33+
}
34+
35+
var context = new DefaultHttpContext
36+
{
37+
RequestServices = new ServiceCollection()
38+
.AddLogging()
39+
.BuildServiceProvider()
40+
};
41+
var next = new RequestDelegate(_ => throw errorException);
42+
var middleware = new ErrorExceptionHandlerMiddleware(next);
43+
44+
// Act
45+
await middleware.InvokeAsync(context);
46+
47+
// Assert
48+
context.Response.StatusCode.Should().Be((int)expectedHttpStatusCode);
49+
}
50+
}

src/Wemogy.AspNet.Tests/Middlewares/ErrorHandlerMiddlewareTests.cs

Lines changed: 0 additions & 117 deletions
This file was deleted.
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Net;
4+
using System.Threading;
5+
using System.Threading.Tasks;
6+
using FluentAssertions;
7+
using FluentValidation;
8+
using FluentValidation.Results;
9+
using Microsoft.AspNetCore.Http;
10+
using Microsoft.Extensions.DependencyInjection;
11+
using Wemogy.AspNet.Middlewares;
12+
using Wemogy.Core.Errors.Exceptions;
13+
using Xunit;
14+
15+
namespace Wemogy.AspNet.Tests.Middlewares;
16+
17+
public class SystemExceptionHandlerMiddleware
18+
{
19+
[Fact]
20+
public async Task CanceledRequestShouldBeIgnored()
21+
{
22+
// Arrange
23+
var abortedCts = new CancellationTokenSource();
24+
var context = new DefaultHttpContext
25+
{
26+
RequestServices = new ServiceCollection()
27+
.AddLogging()
28+
.BuildServiceProvider(),
29+
RequestAborted = abortedCts.Token
30+
};
31+
var next = new RequestDelegate(
32+
c =>
33+
{
34+
// simulate that somewhere in the pipeline we are checking for cancellation
35+
c.RequestAborted.ThrowIfCancellationRequested();
36+
return Task.CompletedTask;
37+
});
38+
var middleware = new ErrorExceptionHandlerMiddleware(next);
39+
40+
// Act
41+
abortedCts.Cancel(); // simulate that the request was aborted
42+
var exception = await Record.ExceptionAsync(() => middleware.InvokeAsync(context));
43+
44+
// Assert
45+
exception.Should().BeNull();
46+
}
47+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using System.IO;
2+
using System.Net;
3+
using System.Net.Http;
4+
using System.Threading.Tasks;
5+
using FluentAssertions;
6+
using Microsoft.AspNetCore.Http;
7+
using Microsoft.Extensions.DependencyInjection;
8+
using Refit;
9+
using Wemogy.AspNet.Refit;
10+
using Xunit;
11+
12+
namespace Wemogy.AspNet.Tests.Middlewares;
13+
14+
public class RefitExceptionHandlerMiddlewareTests
15+
{
16+
[Theory]
17+
[InlineData(HttpStatusCode.NotFound)]
18+
public async Task AssertStatusCodeForErrorAsync(HttpStatusCode expectedHttpStatusCode)
19+
{
20+
// Arrange
21+
var context = new DefaultHttpContext
22+
{
23+
RequestServices = new ServiceCollection()
24+
.AddLogging()
25+
.BuildServiceProvider()
26+
};
27+
var message = new HttpRequestMessage(HttpMethod.Get, "http://localhost");
28+
var response = new HttpResponseMessage(expectedHttpStatusCode)
29+
{
30+
Content = new StringContent("Bar")
31+
};
32+
var apiException = await ApiException.Create(message, HttpMethod.Get, response, new RefitSettings());
33+
var next = new RequestDelegate(_ => throw apiException);
34+
var middleware = new RefitExceptionHandlerMiddleware(next);
35+
36+
// Act
37+
await middleware.InvokeAsync(context);
38+
39+
// Assert
40+
context.Response.StatusCode.Should().Be((int)expectedHttpStatusCode);
41+
}
42+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
using System;
2+
using System.Net;
3+
using System.Threading.Tasks;
4+
using FluentValidation;
5+
using Microsoft.AspNetCore.Http;
6+
7+
namespace Wemogy.AspNet.FluentValidation
8+
{
9+
public class FluentValidationExceptionHandlerMiddleware
10+
{
11+
private readonly RequestDelegate _next;
12+
13+
public FluentValidationExceptionHandlerMiddleware(RequestDelegate next)
14+
{
15+
_next = next;
16+
}
17+
18+
public async Task InvokeAsync(HttpContext context)
19+
{
20+
try
21+
{
22+
await _next(context);
23+
}
24+
catch (ValidationException exception)
25+
{
26+
var response = context.Response;
27+
response.StatusCode = (int)HttpStatusCode.BadRequest;
28+
await response.WriteAsJsonAsync(exception.Errors);
29+
}
30+
31+
// Catch OperationCanceledException, when the request is aborted
32+
catch (OperationCanceledException)
33+
{
34+
if (context.RequestAborted.IsCancellationRequested)
35+
{
36+
return;
37+
}
38+
39+
throw;
40+
}
41+
}
42+
}
43+
}

src/Wemogy.AspNet/Middlewares/DependencyInjection.cs

Lines changed: 0 additions & 12 deletions
This file was deleted.

src/Wemogy.AspNet/Middlewares/ErrorHandlerMiddleware.cs renamed to src/Wemogy.AspNet/Middlewares/ErrorExceptionHandlerMiddleware.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@
77

88
namespace Wemogy.AspNet.Middlewares
99
{
10-
public class ErrorHandlerMiddleware
10+
public class ErrorExceptionHandlerMiddleware
1111
{
1212
private readonly RequestDelegate _next;
1313

14-
public ErrorHandlerMiddleware(RequestDelegate next)
14+
public ErrorExceptionHandlerMiddleware(RequestDelegate next)
1515
{
1616
_next = next;
1717
}

0 commit comments

Comments
 (0)