Using MediatR behaviors instead of Autofac decorators. Solves #187

This commit is contained in:
Eduard Tomàs 2017-08-10 16:05:42 +02:00
parent 86ca13a578
commit 0c73b09406
4 changed files with 40 additions and 67 deletions

View File

@ -0,0 +1,23 @@
using MediatR;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Ordering.API.Infrastructure.Behaviors
{
public class LoggingBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
{
private readonly ILogger<LoggingBehavior<TRequest, TResponse>> _logger;
public LoggingBehavior(ILogger<LoggingBehavior<TRequest, TResponse>> logger) => _logger = logger;
public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next)
{
_logger.LogInformation($"Handling {typeof(TRequest).Name}");
var response = await next();
_logger.LogInformation($"Handled {typeof(TResponse).Name}");
return response;
}
}
}

View File

@ -1,33 +1,23 @@
using FluentValidation; using FluentValidation;
using MediatR; using MediatR;
using Microsoft.Extensions.Logging;
using Ordering.Domain.Exceptions; using Ordering.Domain.Exceptions;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Ordering.API.Application.Decorators namespace Ordering.API.Infrastructure.Behaviors
{ {
public class ValidatorDecorator<TRequest, TResponse> public class ValidatorBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
: IAsyncRequestHandler<TRequest, TResponse>
where TRequest : IRequest<TResponse>
{ {
private readonly IAsyncRequestHandler<TRequest, TResponse> _inner;
private readonly IValidator<TRequest>[] _validators; private readonly IValidator<TRequest>[] _validators;
public ValidatorBehavior(IValidator<TRequest>[] validators) => _validators = validators;
public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next)
public ValidatorDecorator(
IAsyncRequestHandler<TRequest, TResponse> inner,
IValidator<TRequest>[] validators)
{
_inner = inner;
_validators = validators;
}
public async Task<TResponse> Handle(TRequest message)
{ {
var failures = _validators var failures = _validators
.Select(v => v.Validate(message)) .Select(v => v.Validate(request))
.SelectMany(result => result.Errors) .SelectMany(result => result.Errors)
.Where(error => error != null) .Where(error => error != null)
.ToList(); .ToList();
@ -37,9 +27,8 @@ namespace Ordering.API.Application.Decorators
throw new OrderingDomainException( throw new OrderingDomainException(
$"Command Validation Errors for type {typeof(TRequest).Name}", new ValidationException("Validation exception", failures)); $"Command Validation Errors for type {typeof(TRequest).Name}", new ValidationException("Validation exception", failures));
} }
var response = await _inner.Handle(message);
var response = await next();
return response; return response;
} }
} }

View File

@ -1,34 +0,0 @@
namespace Microsoft.eShopOnContainers.Services.Ordering.API.Application.Decorators
{
using Extensions.Logging;
using MediatR;
using System.Threading.Tasks;
public class LogDecorator<TRequest, TResponse>
: IAsyncRequestHandler<TRequest, TResponse>
where TRequest : IRequest<TResponse>
{
private readonly IAsyncRequestHandler<TRequest, TResponse> _inner;
private readonly ILogger<LogDecorator<TRequest, TResponse>> _logger;
public LogDecorator(
IAsyncRequestHandler<TRequest, TResponse> inner,
ILogger<LogDecorator<TRequest, TResponse>> logger)
{
_inner = inner;
_logger = logger;
}
public async Task<TResponse> Handle(TRequest message)
{
_logger.LogInformation($"Executing command {_inner.GetType().FullName}");
var response = await _inner.Handle(message);
_logger.LogInformation($"Command executed successfully {_inner.GetType().FullName}");
return response;
}
}
}

View File

@ -3,11 +3,9 @@ using Autofac.Core;
using FluentValidation; using FluentValidation;
using MediatR; using MediatR;
using Microsoft.eShopOnContainers.Services.Ordering.API.Application.Commands; 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.DomainEventHandlers.OrderStartedEvent;
using Ordering.API.Application.Validations; using Ordering.API.Application.Validations;
using Ordering.Domain.Events; using Ordering.API.Infrastructure.Behaviors;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
@ -33,7 +31,7 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Autof
.Where(i => i.IsClosedTypeOf(typeof(IAsyncNotificationHandler<>))) .Where(i => i.IsClosedTypeOf(typeof(IAsyncNotificationHandler<>)))
.Select(i => new KeyedService("IAsyncNotificationHandler", i))) .Select(i => new KeyedService("IAsyncNotificationHandler", i)))
.AsImplementedInterfaces(); .AsImplementedInterfaces();
builder builder
.RegisterAssemblyTypes(typeof(CreateOrderCommandValidator).GetTypeInfo().Assembly) .RegisterAssemblyTypes(typeof(CreateOrderCommandValidator).GetTypeInfo().Assembly)
@ -45,25 +43,22 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API.Infrastructure.Autof
{ {
var componentContext = context.Resolve<IComponentContext>(); var componentContext = context.Resolve<IComponentContext>();
return t => { object o; return componentContext.TryResolve(t, out o) ? o : null; }; return t => { object o; return componentContext.TryResolve(t, out o) ? o : null; };
}); });
builder.Register<MultiInstanceFactory>(context => builder.Register<MultiInstanceFactory>(context =>
{ {
var componentContext = context.Resolve<IComponentContext>(); var componentContext = context.Resolve<IComponentContext>();
return t => (IEnumerable<object>)componentContext.Resolve(typeof(IEnumerable<>).MakeGenericType(t)); return t =>
{
var resolved = (IEnumerable<object>)componentContext.Resolve(typeof(IEnumerable<>).MakeGenericType(t));
return resolved;
};
}); });
builder.RegisterGeneric(typeof(LoggingBehavior<,>)).As(typeof(IPipelineBehavior<,>));
builder.RegisterGeneric(typeof(ValidatorBehavior<,>)).As(typeof(IPipelineBehavior<,>));
builder.RegisterGenericDecorator(typeof(LogDecorator<,>),
typeof(IAsyncRequestHandler<,>),
"IAsyncRequestHandler")
.Keyed("handlerDecorator", typeof(IAsyncRequestHandler<,>));
builder.RegisterGenericDecorator(typeof(ValidatorDecorator<,>),
typeof(IAsyncRequestHandler<,>),
fromKey: "handlerDecorator");
} }
} }
} }