gpt4 book ai didi

c# - 在 MediatR 管道上使用多个 FluentValidator

转载 作者:行者123 更新时间:2023-12-01 23:14:02 25 4
gpt4 key购买 nike

我有这样的 MediatR 管道行为:

public class FailFastRequestBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
{
private readonly IEnumerable<IValidator> _validators;

public FailFastRequestBehavior(IEnumerable<IValidator<TRequest>> validators)
{
_validators = validators;
}

public Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
{
var failures = _validators
.Select(async v => await v.ValidateAsync(request))
.SelectMany(result => result.Result.Errors)
.Where(f => f != null);


return failures.Any()
? Errors(failures)
: next();
}

...
}

MediatR 命令如下:

public class MyUseCase
{
public class Command : IRequest<CommandResponse>
{
...
}

public class Validator : AbstractValidator<Command>
{
...
}

public class Handler<T>: IRequestHandler<T, CommandResponse>
{
...
}
}

验证器在 Startup.cs 上注册,如下所示:

        AssemblyScanner
.FindValidatorsInAssembly(Assembly.GetAssembly(typeof(MyUseCase)))
.ForEach(result =>
services.AddScoped(result.InterfaceType, result.ValidatorType));

这对于 MyUseCase.Validator 效果很好,它被注入(inject)到管道上并执行,验证 MyUseCase.Command

但这是一个大型应用程序,许多命令都有共同的属性,即每个订单操作都会收到一个OrderId,我必须检查该Id是否有效,该实体是否存在于数据库中,如果经过身份验证的用户是正在修改的订单的所有者等。

所以我尝试创建以下接口(interface)和验证器:

public interface IOrder
{
string OrderId { get; set; }
}

public class IOrderValidator : AbstractValidator<IOrder>
{
public IOrderValidator()
{
CascadeMode = CascadeMode.StopOnFirstFailure;

RuleFor(x => x.OrderId)
.Rule1()
.Rule2()
.Rule3()
.RuleN()
}
}

最后我将命令更改为:

public class MyUseCase
{
public class Command : IRequest<CommandResponse>: IOrder
{
...
}

public class Validator : AbstractValidator<Command>
{
...
}

public class Handler<T>: IRequestHandler<T, CommandResponse>
{
...
}
}

问题是 IOrderValidator 没有注入(inject)管道,只有 MyUseCase.Validator 注入(inject)。

我是否在这里遗漏了一些东西,或者甚至可以在管道中注入(inject)多个验证器?

最佳答案

服务解析取决于您使用的 DI 容器。看来您使用内置的.NET Core容器,并且它无法解析逆变接口(interface)。

考虑Simple Injector相反,因为它知道如何处理逆变。此示例代码将解析您需要的所有验证器:

[Fact]
public void Test()
{
var container = new SimpleInjector.Container();

container.Collection.Append<IValidator<IOrder>, OrderValidator>();
container.Collection.Append<IValidator<Command>, CommandValidator>();

var validators = container.GetAllInstances<IValidator<Command>>();

validators.Should().HaveCount(2);
}

或者,您必须显式注册验证器,并使用它们必须适用的所有命令进行参数化:

[Fact]
public void Test()
{
var provider = new ServiceCollection()
.AddTransient(typeof(IValidator<Command>), typeof(OrderValidator))
.AddTransient(typeof(IValidator<Command>), typeof(CommandValidator))
.BuildServiceProvider();

var validators = provider.GetServices<IValidator<Command>>();

validators.Should().HaveCount(2);
}

请注意在简单注入(inject)器和 .NET Core DI 容器的情况下注册 OrderValidatorIOrderCommand 之间的区别:

container.Collection.Append<IValidator<IOrder>, OrderValidator>();
servcies.AddTransient(typeof(IValidator<Command>), typeof(OrderValidator))

假设定义了以下类和接口(interface):

interface IOrder
{
}

class Command : IRequest<CommandResponse>, IOrder
{
}

class CommandResponse
{
}

class OrderValidator : AbstractValidator<IOrder>
{
}

class CommandValidator : AbstractValidator<Command>
{
}

关于c# - 在 MediatR 管道上使用多个 FluentValidator,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58485674/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com