Merge pull request #133 from dotnet/Validation-decorator-integration
#39 Validation decorator integration
This commit is contained in:
commit
92501eb0d9
@ -0,0 +1,45 @@
|
||||
using FluentValidation;
|
||||
using MediatR;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ordering.API.Application.Decorators
|
||||
{
|
||||
public class ValidatorDecorator<TRequest, TResponse>
|
||||
: IAsyncRequestHandler<TRequest, TResponse>
|
||||
where TRequest : IAsyncRequest<TResponse>
|
||||
{
|
||||
private readonly IAsyncRequestHandler<TRequest, TResponse> _inner;
|
||||
private readonly IValidator<TRequest>[] _validators;
|
||||
|
||||
|
||||
public ValidatorDecorator(
|
||||
IAsyncRequestHandler<TRequest, TResponse> inner,
|
||||
IValidator<TRequest>[] validators)
|
||||
{
|
||||
_inner = inner;
|
||||
_validators = validators;
|
||||
}
|
||||
|
||||
public async Task<TResponse> Handle(TRequest message)
|
||||
{
|
||||
var failures = _validators
|
||||
.Select(v => v.Validate(message))
|
||||
.SelectMany(result => result.Errors)
|
||||
.Where(error => error != null)
|
||||
.ToList();
|
||||
|
||||
if (failures.Any())
|
||||
{
|
||||
throw new ValidationException(
|
||||
$"Command Validation Errors for type {typeof(TRequest).Name}", failures);
|
||||
}
|
||||
|
||||
var response = await _inner.Handle(message);
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
using FluentValidation;
|
||||
using MediatR;
|
||||
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using static Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands.CreateOrderCommand;
|
||||
|
||||
namespace Ordering.API.Application.Validations
|
||||
{
|
||||
public class CreateOrderCommandValidator : AbstractValidator<CreateOrderCommand>
|
||||
{
|
||||
public CreateOrderCommandValidator()
|
||||
{
|
||||
RuleFor(order => order.City).NotEmpty();
|
||||
RuleFor(order => order.Street).NotEmpty();
|
||||
RuleFor(order => order.State).NotEmpty();
|
||||
RuleFor(order => order.Country).NotEmpty();
|
||||
RuleFor(order => order.ZipCode).NotEmpty();
|
||||
RuleFor(order => order.CardNumber).NotEmpty().Length(12, 19);
|
||||
RuleFor(order => order.CardHolderName).NotEmpty();
|
||||
RuleFor(order => order.CardExpiration).NotEmpty().Must(BeValidExpirationDate).WithMessage("Please specify a valid card expiration date");
|
||||
RuleFor(order => order.CardSecurityNumber).NotEmpty().Length(3);
|
||||
RuleFor(order => order.CardTypeId).NotEmpty();
|
||||
RuleFor(order => order.OrderItems).Must(ContainOrderItems).WithMessage("No order items found");
|
||||
}
|
||||
|
||||
private bool BeValidExpirationDate(DateTime dateTime)
|
||||
{
|
||||
return dateTime >= DateTime.UtcNow;
|
||||
}
|
||||
|
||||
private bool ContainOrderItems(IEnumerable<OrderItemDTO> orderItems)
|
||||
{
|
||||
return orderItems.Any();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
using FluentValidation;
|
||||
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ordering.API.Application.Validations
|
||||
{
|
||||
public class IdentifierCommandValidator : AbstractValidator<IdentifiedCommand<CreateOrderCommand,bool>>
|
||||
{
|
||||
public IdentifierCommandValidator()
|
||||
{
|
||||
RuleFor(customer => customer.Id).NotEmpty();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,9 +1,12 @@
|
||||
using Autofac;
|
||||
using Autofac.Core;
|
||||
using FluentValidation;
|
||||
using MediatR;
|
||||
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands;
|
||||
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Decorators;
|
||||
using Ordering.API.Application.Decorators;
|
||||
using Ordering.API.Application.DomainEventHandlers.OrderStartedEvent;
|
||||
using Ordering.API.Application.Validations;
|
||||
using Ordering.Domain.Events;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@ -24,11 +27,17 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Autof
|
||||
.Where(i => i.IsClosedTypeOf(typeof(IAsyncRequestHandler<,>)))
|
||||
.Select(i => new KeyedService("IAsyncRequestHandler", i)));
|
||||
|
||||
// Register all the Domain Event Handler classes (they implement IAsyncNotificationHandler<>) in assembly holding the Domain Events
|
||||
// Register all the event classes (they implement IAsyncNotificationHandler) in assembly holding the Commands
|
||||
builder.RegisterAssemblyTypes(typeof(ValidateOrAddBuyerAggregateWhenOrderStartedDomainEventHandler).GetTypeInfo().Assembly)
|
||||
.As(o => o.GetInterfaces()
|
||||
.Where(i => i.IsClosedTypeOf(typeof(IAsyncNotificationHandler<>)))
|
||||
.Select(i => new KeyedService("IAsyncNotificationHandler", i)));
|
||||
|
||||
builder
|
||||
.RegisterAssemblyTypes(typeof(ValidateOrAddBuyerAggregateWhenOrderStartedDomainEventHandler).GetTypeInfo().Assembly)
|
||||
.Where(t => t.IsClosedTypeOf(typeof(IAsyncNotificationHandler<>)))
|
||||
.AsImplementedInterfaces();
|
||||
.RegisterAssemblyTypes(typeof(CreateOrderCommandValidator).GetTypeInfo().Assembly)
|
||||
.Where(t => t.IsClosedTypeOf(typeof(IValidator<>)))
|
||||
.AsImplementedInterfaces();
|
||||
|
||||
|
||||
builder.Register<SingleInstanceFactory>(context =>
|
||||
{
|
||||
@ -44,9 +53,16 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Autof
|
||||
return t => (IEnumerable<object>)componentContext.Resolve(typeof(IEnumerable<>).MakeGenericType(t));
|
||||
});
|
||||
|
||||
|
||||
|
||||
builder.RegisterGenericDecorator(typeof(LogDecorator<,>),
|
||||
typeof(IAsyncRequestHandler<,>),
|
||||
"IAsyncRequestHandler");
|
||||
"IAsyncRequestHandler")
|
||||
.Keyed("handlerDecorator", typeof(IAsyncRequestHandler<,>));
|
||||
|
||||
builder.RegisterGenericDecorator(typeof(ValidatorDecorator<,>),
|
||||
typeof(IAsyncRequestHandler<,>),
|
||||
fromKey: "handlerDecorator");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,8 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FluentValidation.AspNetCore" Version="6.4.0" />
|
||||
<PackageReference Include="FluentValidation.MVC6" Version="6.4.0" />
|
||||
<PackageReference Include="MediatR.Extensions.Microsoft.DependencyInjection" Version="1.1.0" />
|
||||
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="4.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.1.0" />
|
||||
|
Loading…
x
Reference in New Issue
Block a user