Декоратор FluentValidation не работает с autofac и посредником

Я пытаюсь настроить приложение ASP.NET Core с шаблоном CQRS. Чтобы добиться этого, я использую следующие библиотеки:

"Autofac.Extensions.DependencyInjection": "4.0.0-rc3-280",
"FluentValidation": "6.4.0-beta3",
"MediatR": "2.1.0"

Я выполнил все необходимые настройки, Mediatr работает, внедрение зависимостей работает, однако мой код не проходит проверку перед переходом в обработчик. Думаю, у меня проблема с регистрацией декоратора валидации. Поскольку большинство библиотек, которые я использую, недавно обновились и сильно изменились для поддержки ASP.NET Core. Что мне не хватает в конфигурации? Как это должно быть?

Моя конфигурация

public IServiceProvider ConfigureServices(IServiceCollection services)
    {

        var builder = new ContainerBuilder();
        builder.RegisterAssemblyTypes(typeof(IMediator).GetTypeInfo().Assembly).AsImplementedInterfaces();
        builder.RegisterAssemblyTypes(typeof(GetUserByEmailQuery).GetTypeInfo().Assembly).AsImplementedInterfaces();

        builder.Register<SingleInstanceFactory>(ctx =>
        {
            var c = ctx.Resolve<IComponentContext>();
            return t => c.Resolve(t);
        });
        builder.Register<MultiInstanceFactory>(ctx =>
        {
            var c = ctx.Resolve<IComponentContext>();
            return t => (IEnumerable<object>)c.Resolve(typeof(IEnumerable<>).MakeGenericType(t));
        });


        builder.RegisterGenericDecorator(
            typeof(MediatorPipeline<,>),
            typeof(IRequestHandler<,>), fromKey: "handler", toKey: "Validator")
            .Keyed("MediatorPipeline", typeof(IRequestHandler<,>))
            .InstancePerLifetimeScope();


        //register validator decorator
        builder.RegisterGenericDecorator(
            typeof(ValidatorHandler<,>),
            typeof(IRequestHandler<,>),
            "Validator")
            .InstancePerLifetimeScope();


        builder.Populate(services);
        var container = builder.Build();

        return container.Resolve<IServiceProvider>();
    }

MediatorPipeline (Не уверен, действительно ли он мне нужен.)

public class MediatorPipeline<TRequest, TResponse>  : IRequestHandler<TRequest, TResponse>  where TRequest : IRequest<TResponse>
{

    private readonly IRequestHandler<TRequest, TResponse> _inner;
    private readonly IPreRequestHandler<TRequest>[] _preRequestHandlers;
    private readonly IPostRequestHandler<TRequest, TResponse>[] _postRequestHandlers;

    public MediatorPipeline(IRequestHandler<TRequest, TResponse> inner, IPreRequestHandler<TRequest>[] preRequestHandlers, IPostRequestHandler<TRequest, TResponse>[] postRequestHandlers)
    {
        _inner = inner;
        _preRequestHandlers = preRequestHandlers;
        _postRequestHandlers = postRequestHandlers;
    }

    public TResponse Handle(TRequest message)
    {

        foreach (var preRequestHandler in _preRequestHandlers)
        {
            preRequestHandler.Handle(message);
        }

        var result = _inner.Handle(message);

        foreach (var postRequestHandler in _postRequestHandlers)
        {
            postRequestHandler.Handle(message, result);
        }

        return result;
    }
}

ValidatorHandler

public class ValidatorHandler<TRequest, TResponse> : IRequestHandler<TRequest, TResponse>  where TRequest : IRequest<TResponse>
{

    private readonly IRequestHandler<TRequest, TResponse> _inner;
    private readonly IValidator<TRequest>[] _validators;

    public ValidatorHandler(IRequestHandler<TRequest, TResponse> inner,  IValidator<TRequest>[] validators)
    {
        _inner = inner;
        _validators = validators;
    }

    public TResponse Handle(TRequest message)
    {
        var context = new ValidationContext(message);

        var failures = _validators
            .Select(v => v.Validate(context))
            .SelectMany(result => result.Errors)
            .Where(f => f != null)
            .ToList();

        if (failures.Any())
            throw new ValidationException(failures);

        return _inner.Handle(message);
    }
}

GetUserByEmailQuery.cs

public class GetUserByEmailQuery : IRequest<UserDomain>
{
    public string UserEmail { get; set; }
}

public class GetUserByEmailQueryValidator : AbstractValidator<GetUserByEmailQuery>
{
    public GetUserByEmailQueryValidator()
    {
        RuleFor(q => q.UserEmail).NotNull().WithMessage("Email alanı boş bırakılamaz!");
    }
    public bool Handle(GetUserByEmailQuery message)
    {

        return true;
    }
}
public class GetUserByEmailQueryHandler : IRequestHandler<GetUserByEmailQuery, UserDomain>
{
    private readonly AuthDbContext _context;

    public GetUserByEmailQueryHandler(AuthDbContext context)
    {
        _context = context;
    }

    public UserDomain Handle(GetUserByEmailQuery message)
    {
        var authUser = _context.Users.Where(x => x.Email.Equals(message.UserEmail)).Include(y => y.UserMeta).Include(z => z.UserRole).FirstOrDefault();
            var userDomain = Mapper.Map<UserDomain>(authUser);
            return userDomain;


    }
}

в этом классе мой код идет прямо в public UserDomain Handle(GetUserByEmailQuery message) без проверки.


person gorkemyontem    schedule 09.07.2016    source источник
comment
Если вы разрешаете один обработчик запросов вручную, есть ли у него декоратор?   -  person Travis Illig    schedule 11.07.2016


Ответы (1)


Проблема заключается в этой строке:

typeof(IRequestHandler<,>), fromKey: "handler", toKey: "Validator")

Он не может найти handler ключ.
Поэтому я разделил регистрацию типов, сначала зарегистрировав все типы в вашей сборке, но исключив RequestHandlers. Затем зарегистрировали RequestHandlers с ключом handler.

public IServiceProvider ConfigureServices(IServiceCollection services)
{

    var builder = new ContainerBuilder();
    builder.RegisterAssemblyTypes(typeof(IMediator).GetTypeInfo().Assembly).AsImplementedInterfaces();
    builder.RegisterAssemblyTypes(typeof(GetUserByEmailQuery).GetTypeInfo().Assembly)
            .Where(t => !t.IsClosedTypeOf(typeof(IRequestHandler<,>)))
            .AsImplementedInterfaces();

    builder.Register<SingleInstanceFactory>(ctx =>
    {
        var c = ctx.Resolve<IComponentContext>();
        return t => c.Resolve(t);
    });
    builder.Register<MultiInstanceFactory>(ctx =>
    {
        var c = ctx.Resolve<IComponentContext>();
        return t => (IEnumerable<object>)c.Resolve(typeof(IEnumerable<>).MakeGenericType(t));
    });

    builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())
            .As(type => type.GetInterfaces()
                .Where(interfaceType => interfaceType.IsClosedTypeOf(typeof(IRequestHandler<,>)))
                .Select(interfaceType => new KeyedService("handler", interfaceType)))
            .InstancePerLifetimeScope();

    builder.RegisterGenericDecorator(
        typeof(MediatorPipeline<,>),
        typeof(IRequestHandler<,>), fromKey: "handler", toKey: "Validator")
        .Keyed("MediatorPipeline", typeof(IRequestHandler<,>))
        .InstancePerLifetimeScope();

    //register validator decorator
    builder.RegisterGenericDecorator(
        typeof(ValidatorHandler<,>),
        typeof(IRequestHandler<,>),
        "Validator")
        .InstancePerLifetimeScope();


    builder.Populate(services);
    var container = builder.Build();

    return container.Resolve<IServiceProvider>();
}

Надеюсь это поможет!

person Arne    schedule 11.09.2016