0

我刚刚开始在 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 { "title": "Mr", "firstName": "Paul", "surname": "" }

我得到一个 200。 CreatePersonH​​andler.Handle() 被调用,但 CreatePersonValidator() 从未被调用。

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

4

1 回答 1

0

我建议您阅读有关如何在 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。

于 2017-07-13T03:25:48.010 回答