-
-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Wired up automatic validation, and registration of all validators in …
…all modules
- Loading branch information
1 parent
5bab977
commit 7d6ce60
Showing
17 changed files
with
646 additions
and
54 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
using CarsApi; | ||
using Infrastructure.WebApi.Common; | ||
|
||
namespace ApiHost1; | ||
|
||
public static class HostedModules | ||
{ | ||
public static SubDomainModules Get() | ||
{ | ||
// EXTEND: Add the sub domain of each API, to host in this project. | ||
// NOTE: The order of these registrations will matter for some dependencies | ||
var modules = new SubDomainModules(); | ||
modules.Register(new CarsApiModule()); | ||
modules.Register(new TestingOnlyApiModule()); | ||
|
||
return modules; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
using FluentValidation; | ||
using Infrastructure.WebApi.Interfaces.Operations.Cars; | ||
|
||
namespace CarsApi.Cars; | ||
|
||
public class GetCarRequestValidator : AbstractValidator<GetCarRequest> | ||
{ | ||
public GetCarRequestValidator() | ||
{ | ||
RuleFor(req => req.Id).NotEmpty().Matches(@"[\d]{1,3}"); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
namespace Common.Extensions; | ||
|
||
public static class CollectionExtensions | ||
{ | ||
public static bool HasAny<T>(this IEnumerable<T> collection) | ||
{ | ||
return !collection.HasNone(); | ||
} | ||
|
||
public static bool HasNone<T>(this IEnumerable<T> collection) | ||
{ | ||
return !collection.Any(); | ||
} | ||
} |
98 changes: 98 additions & 0 deletions
98
src/Infrastructure.WebApi.Common.UnitTests/ServiceCollectionExtensionsSpec.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
using System.Reflection; | ||
using FluentAssertions; | ||
using FluentValidation; | ||
using Infrastructure.WebApi.Interfaces; | ||
using Microsoft.AspNetCore.Http; | ||
using Microsoft.Extensions.DependencyInjection; | ||
|
||
namespace Infrastructure.WebApi.Common.UnitTests; | ||
|
||
[Trait("Category", "Unit")] | ||
public class ServiceCollectionExtensionsSpec | ||
{ | ||
[Fact] | ||
public void WhenRegisterValidators_ThenRegistersInContainer() | ||
{ | ||
var services = new ServiceCollection(); | ||
|
||
services.RegisterValidators(new[] { typeof(ServiceCollectionExtensionsSpec).Assembly }, out var validators); | ||
|
||
services.Should().ContainSingle(service => service.ImplementationType == typeof(TestRequestValidator)); | ||
} | ||
|
||
[Fact] | ||
public void WhenAddValidatorBehaviorsAndNoRegisteredValidators_ThenRegistersNoBehaviors() | ||
{ | ||
var configuration = new MediatRServiceConfiguration(); | ||
var assemblies = new[] { typeof(ServiceCollectionExtensionsSpec).Assembly }; | ||
|
||
configuration.AddValidatorBehaviors(Enumerable.Empty<Type>(), assemblies); | ||
|
||
configuration.BehaviorsToRegister.Should().BeEmpty(); | ||
} | ||
|
||
|
||
[Fact] | ||
public void WhenAddValidatorBehaviorsAndNoRequestTypes_ThenRegistersNoBehaviors() | ||
{ | ||
var configuration = new MediatRServiceConfiguration(); | ||
var validators = new[] { typeof(TestRequestValidator) }; | ||
|
||
configuration.AddValidatorBehaviors(validators, Enumerable.Empty<Assembly>()); | ||
|
||
configuration.BehaviorsToRegister.Should().BeEmpty(); | ||
} | ||
|
||
|
||
[Fact] | ||
public void WhenAddValidatorBehaviorsAndNoMatchingValidators_ThenRegistersNoBehaviors() | ||
{ | ||
var configuration = new MediatRServiceConfiguration(); | ||
var validators = new[] { typeof(TestRequestValidator2) }; | ||
var assemblies = new[] { typeof(ServiceCollectionExtensionsSpec).Assembly }; | ||
|
||
configuration.AddValidatorBehaviors(validators, assemblies); | ||
|
||
configuration.BehaviorsToRegister.Should().BeEmpty(); | ||
} | ||
|
||
[Fact] | ||
public void WhenAddValidatorBehaviors_ThenRegistersBehavior() | ||
{ | ||
var configuration = new MediatRServiceConfiguration(); | ||
var validators = new[] { typeof(TestRequestValidator) }; | ||
var assemblies = new[] { typeof(ServiceCollectionExtensionsSpec).Assembly }; | ||
|
||
configuration.AddValidatorBehaviors(validators, assemblies); | ||
|
||
var expectedBehaviorImplementationType = | ||
typeof(ValidationBehavior<,>).MakeGenericType(typeof(TestRequest), typeof(TestResponse)); | ||
configuration.BehaviorsToRegister.Should() | ||
.ContainSingle(behavior => behavior.ImplementationType == expectedBehaviorImplementationType); | ||
} | ||
|
||
public class TestRequestValidator : AbstractValidator<TestRequest> | ||
{ | ||
} | ||
|
||
public class TestRequestValidator2 : AbstractValidator<TestRequest2> | ||
{ | ||
} | ||
|
||
public class TestApiWithoutMethods : IWebApiService | ||
{ | ||
} | ||
|
||
public class TestApi : IWebApiService | ||
{ | ||
[WebApiRoute("/aroute", WebApiOperation.Get)] | ||
public Task<IResult> Get(TestRequest request, CancellationToken cancellationToken) | ||
{ | ||
return Task.FromResult(Results.Ok("amessage")); | ||
} | ||
} | ||
|
||
public class TestRequest2 : IWebRequest<TestResponse> | ||
{ | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
69 changes: 69 additions & 0 deletions
69
src/Infrastructure.WebApi.Common.UnitTests/ValidationBehaviorSpec.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
using FluentAssertions; | ||
using FluentValidation; | ||
using FluentValidation.Results; | ||
using Infrastructure.WebApi.Interfaces; | ||
using Microsoft.AspNetCore.Http; | ||
using Moq; | ||
|
||
namespace Infrastructure.WebApi.Common.UnitTests; | ||
|
||
[Trait("Category", "Unit")] | ||
public class ValidationBehaviorSpec | ||
{ | ||
private readonly ValidationBehavior<TestRequest, TestResponse> _behavior; | ||
private readonly Mock<IValidator<TestRequest>> _validator; | ||
|
||
public ValidationBehaviorSpec() | ||
{ | ||
_validator = new Mock<IValidator<TestRequest>>(); | ||
_behavior = new ValidationBehavior<TestRequest, TestResponse>(_validator.Object); | ||
} | ||
|
||
[Fact] | ||
public async Task WhenHandleAndValidatorPasses_ThenExecutesMiddleware() | ||
{ | ||
var request = new TestRequest(); | ||
var wasNextCalled = false; | ||
_validator.Setup(val => val.ValidateAsync(It.IsAny<TestRequest>(), It.IsAny<CancellationToken>())) | ||
.Returns(Task.FromResult(new ValidationResult())); | ||
|
||
var result = await _behavior.Handle(request, () => | ||
{ | ||
wasNextCalled = true; | ||
return Task.FromResult(Results.Ok()); | ||
}, CancellationToken.None); | ||
|
||
wasNextCalled.Should().BeTrue(); | ||
_validator.Verify(val => val.ValidateAsync(request, CancellationToken.None)); | ||
result.Should().Be(Results.Ok()); | ||
} | ||
|
||
[Fact] | ||
public async Task WhenHandleAndValidatorFails_ThenReturnsBadRequest() | ||
{ | ||
var request = new TestRequest(); | ||
var wasNextCalled = false; | ||
var errors = new ValidationResult(new List<ValidationFailure> | ||
{ new("aproperty", "anerror") }); | ||
_validator.Setup(val => val.ValidateAsync(It.IsAny<TestRequest>(), It.IsAny<CancellationToken>())) | ||
.Returns(Task.FromResult(errors)); | ||
|
||
var result = await _behavior.Handle(request, () => | ||
{ | ||
wasNextCalled = true; | ||
return Task.FromResult(Results.Ok()); | ||
}, CancellationToken.None); | ||
|
||
wasNextCalled.Should().BeFalse(); | ||
_validator.Verify(val => val.ValidateAsync(request, CancellationToken.None)); | ||
result.Should().BeEquivalentTo(TypedResults.BadRequest(errors.Errors)); | ||
} | ||
} | ||
|
||
public class TestRequest : IWebRequest<TestResponse> | ||
{ | ||
} | ||
|
||
public class TestResponse : IWebResponse | ||
{ | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
using System.Reflection; | ||
using Microsoft.AspNetCore.Builder; | ||
using Microsoft.Extensions.Configuration; | ||
using Microsoft.Extensions.DependencyInjection; | ||
|
||
namespace Infrastructure.WebApi.Common; | ||
|
||
public interface ISubDomainModule | ||
{ | ||
public Assembly ApiAssembly { get; } | ||
|
||
public Action<WebApplication> MinimalApiRegistrationFunction { get; } | ||
public Action<ConfigurationManager, IServiceCollection>? RegisterServicesFunction { get; } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.