使用autofac在MediatR和ASP.NET Core中连接验证

时间:2017-07-06 04:44:22

标签: asp.net-core asp.net-core-mvc autofac fluentvalidation mediatr

我刚开始在asp.net核心项目中使用MediatR,并且正在努力加强验证......

这是我的控制器:

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);
    }
}

...但我正在努力使用autofac在Startup.ConfigureServices中正确连接验证:

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时 {     “标题”:“先生”,     “firstName”:“保罗”,     “姓”: ”” }

我得到200。 调用CreatePersonH​​andler.Handle()但从不调用CreatePersonValidator()。

我在Startup.ConfigureServices()中遗漏了什么?

1 个答案:

答案 0 :(得分:0)

我建议您阅读just happens to create an AssetBundle for you,了解如何在Autofac中连接装饰器。

装饰器使用命名服务来解析装饰服务。

例如,在您的代码中:

dropwizard-swagger

您指示Autofac将builder.RegisterGenericDecorator( typeof(ValidatorHandler<,>), typeof(IRequestHandler<,>), "Validator").InstancePerLifetimeScope(); 用作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(); 参数的名称有助于理解装饰器如何与Autofac一起使用。