Подключение проверки в MediatR и ASP.NET Core с помощью autofac

Я только начал использовать MediatR в основном проекте asp.net и изо всех сил пытаюсь подключить проверку...

Вот мой контроллер:

public class PersonController : Controller
{
    IMediator mediator;
    public PersonController(IMediator mediator)
    {
        this.mediator = mediator;
    }

    [HttpPost]
    public async Task<ActionResult> Post([FromBody]CreatePerson model)
    {
        var success = await mediator.Send(model);
        if (success)
        {
            return Ok();
        }
        else
        {
            return BadRequest();
        }
    }
}

... и команда CreatePerson, проверка (через FluentValidation) и обработчик запросов:

public class CreatePerson : IRequest<bool>
{
    public string Title { get; set; }

    public string FirstName { get; set; }

    public string Surname { get; set; }
}

public class CreatePersonValidator : AbstractValidator<CreatePerson>
{
    public CreatePersonValidator()
    {
        RuleFor(m => m.FirstName).NotEmpty().Length(1, 50);
        RuleFor(m => m.Surname).NotEmpty().Length(3, 50);
    }
}

public class CreatePersonHandler : IRequestHandler<CreatePerson, bool>
{

    public CreatePersonHandler()
    {
    }

    public bool Handle(CreatePerson message)
    {
        // do some stuff
        return true;
    }

}

У меня есть этот общий обработчик проверки:

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)
    {
        this.inner = inner;
        this.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);
    }
}

... но я изо всех сил пытаюсь правильно подключить проверку в Startup.ConfigureServices с помощью autofac:

public IServiceProvider ConfigureServices(IServiceCollection services)
{
    // Add framework services.
    services.AddMvc();

    var builder = new ContainerBuilder();

    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(typeof(IMediator).GetTypeInfo().Assembly).AsImplementedInterfaces();
    builder.RegisterAssemblyTypes(typeof(CreatePersonHandler).GetTypeInfo().Assembly).AsClosedTypesOf(typeof(IRequestHandler<,>));

    builder.RegisterGenericDecorator(typeof(ValidatorHandler<,>), typeof(IRequestHandler<,>), "Validator").InstancePerLifetimeScope();

    builder.Populate(services);

    var container = builder.Build();
    return container.Resolve<IServiceProvider>();
}

Когда я запускаю приложение и POST /api/person { "title": "Mr", "firstName": "Paul", "surname": "" }

Я получаю 200. CreatePersonHandler.Handle() вызывается, но CreatePersonValidator() никогда не вызывается.

Я что-то упустил в Startup.ConfigureServices()?


person Carl Rippon    schedule 06.07.2017    source источник


Ответы (1)


Я предлагаю вам прочитать официальную документацию о том, как для подключения декораторов в Autofac.

Декораторы используют именованные службы для разрешения декорированных служб.

Например, в вашем фрагменте кода:

builder.RegisterGenericDecorator(
    typeof(ValidatorHandler<,>),
    typeof(IRequestHandler<,>),
    "Validator").InstancePerLifetimeScope();

вы указываете Autofac использовать ValidationHandler<,> в качестве декоратора для IRequestHandler<,> служб, которые были зарегистрированы с именем Validator, что, вероятно, не то, что вам нужно.

Вот как вы можете заставить его работать:

// Register the request handlers as named services
builder
    .RegisterAssemblyTypes(typeof(CreatePersonHandler).GetTypeInfo().Assembly)
    .AsClosedTypesOf(typeof(IRequestHandler<,>))
    .Named("BaseImplementation");

// Register the decorators on top of your request handlers
builder.RegisterGenericDecorator(
    typeof(ValidatorHandler<,>),
    typeof(IRequestHandler<,>),
    fromKey: "BaseImplementation").InstancePerLifetimeScope();

Я считаю, что указание имени параметра fromKey помогает понять, как декораторы работают с Autofac.

person Mickaël Derriey    schedule 13.07.2017