2

我正在使用 Web Api 2、Autofac 和 MediatR (CQRS)。我有一个具有前置/后置请求处理程序的调解器管道。这一切都很好。我现在正在尝试连接 Validation 并用它来装饰管道。

这是我的 Autofac DI 代码:

public void Configuration(IAppBuilder app)
{
    var config = new HttpConfiguration();
    FluentValidationModelValidatorProvider.Configure(config);
    ConfigureDependencyInjection(app, config);

    WebApiConfig.Register(config);
    app.UseWebApi(config);
}

private static void ConfigureDependencyInjection(IAppBuilder app, HttpConfiguration config)
{
    var builder = new ContainerBuilder();
    builder.RegisterSource(new ContravariantRegistrationSource());
    builder.RegisterAssemblyTypes(typeof(IMediator).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));
    });

    //register all pre handlers
    builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())
        .As(type => type.GetInterfaces()
            .Where(interfacetype => interfacetype.IsClosedTypeOf(typeof(IAsyncPreRequestHandler<>))))
        .InstancePerLifetimeScope();

    //register all post handlers
    builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())
        .As(type => type.GetInterfaces()
            .Where(interfacetype => interfacetype.IsClosedTypeOf(typeof(IAsyncPostRequestHandler<,>))))
        .InstancePerLifetimeScope();

    //register all async handlers
    builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())
        .As(type => type.GetInterfaces()
            .Where(interfaceType => interfaceType.IsClosedTypeOf(typeof(IAsyncRequestHandler<,>)))
            .Select(interfaceType => new KeyedService("asyncRequestHandler", interfaceType)))
        .InstancePerLifetimeScope();

    //register pipeline decorator
    builder.RegisterGenericDecorator(
        typeof(AsyncMediatorPipeline<,>), 
        typeof(IAsyncRequestHandler<,>), 
        "asyncRequestHandler")
        .Keyed("asyncMediatorPipeline", typeof(IAsyncRequestHandler<,>))
        .InstancePerLifetimeScope();

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

    // Register Web API controller in executing assembly.
    builder.RegisterApiControllers(Assembly.GetExecutingAssembly()).InstancePerRequest();

    //register RedStripeDbContext
    builder.RegisterType<RedStripeDbContext>().As<IRedStripeDbContext>().InstancePerRequest();

    builder.RegisterType<AutofacServiceLocator>().AsImplementedInterfaces();
    var container = builder.Build();

    config.DependencyResolver = new AutofacWebApiDependencyResolver(container);

    // This should be the first middleware added to the IAppBuilder.
    app.UseAutofacMiddleware(container);

    // Make sure the Autofac lifetime scope is passed to Web API.
    app.UseAutofacWebApi(config);
}

这是验证器处理程序:

public class ValidatorHandler<TRequest, TResponse> : IAsyncRequestHandler<TRequest, TResponse> where TRequest : IAsyncRequest<TResponse>
{
    private readonly IAsyncRequestHandler<TRequest, TResponse> _inner;
    private readonly IValidator<TRequest>[] _validators;

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

    public async Task<TResponse> Handle(TRequest request)
    {
        var context = new ValidationContext(request);

        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 await _inner.Handle(request);
    }
}

这是一个示例查询:

[Validator(typeof(GetAccountRequestValidationHandler))]
public class GetAccountRequest : IAsyncRequest<GetAccountResponse>
{
    public int Id { get; set; }
}

这是流利的验证处理程序:

public class GetAccountRequestValidationHandler : AbstractValidator<GetAccountRequest>
{
    public GetAccountRequestValidationHandler()
    {
        RuleFor(m => m.Id).GreaterThan(0).WithMessage("Please specify an id.");
    }

    public Task Handle(GetAccountRequest request)
    {
        Debug.WriteLine("GetAccountPreProcessor Handler");

        return Task.FromResult(true);
    }
}

这是请求处理程序:

public class GetAccountRequestHandler : IAsyncRequestHandler<GetAccountRequest, GetAccountResponse>
{
    private readonly IRedStripeDbContext _dbContext;

    public GetAccountRequestHandler(IRedStripeDbContext redStripeDbContext)
    {
        _dbContext = redStripeDbContext;
    }

    public async Task<GetAccountResponse> Handle(GetAccountRequest message)
    {
        return await _dbContext.Accounts.Where(a => a.AccountId == message.Id)
            .ProjectToSingleOrDefaultAsync<GetAccountResponse>();
    }
}

最后是 Web Api 2 HttpGet 方法:

[Route("{id:int}")]
[HttpGet]
public async Task<IHttpActionResult> GetById([FromUri] GetAccountRequest request)
{
    var model = await _mediator.SendAsync<GetAccountResponse>(request);

    return Ok(model);
}

我在各处都设置了断点,当我到达这个端点时,我首先进入的是 GetAccountRequestValidationHandler。然后我进入 ValidatorHandler 的构造函数。问题是,构造函数的 IValidator[] 验证器参数始终为空。

我一定错过了通过 Autofac 进行流畅验证和注册的东西吗?任何帮助深表感谢。

4

1 回答 1

3

验证器类型必须在 IoC 中注册。将以下内容添加到您的 ConfigureDependencyInjection 方法中应该可以做到。

builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())
  .Where(t => t.Name.EndsWith("ValidationHandler"))
  .AsImplementedInterfaces()
  .InstancePerLifetimeScope();
于 2015-09-18T18:41:51.447 回答