我使用的是内置容器ASP.NET Core和支持"behavior" pipelines的MediatR 3:
public class MyRequest : IRequest<string>
{
// ...
}
public class MyRequestHandler : IRequestHandler<MyRequest, string>
{
public string Handle(MyRequest message)
{
return "Hello!";
}
}
public class MyPipeline<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
{
public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next)
{
var response = await next();
return response;
}
}
// in `Startup.ConfigureServices()`:
services.AddTransient(typeof(IPipelineBehavior<MyRequest,string>), typeof(MyPipeline<MyRequest,string>))
我需要在管道中使用FluentValidation验证器。在MediatR 2中,validation pipeline was created thus:
public class ValidationPipeline<TRequest, TResponse>
: IRequestHandler<TRequest, TResponse>
where TRequest : IRequest<TResponse>
{
public ValidationPipeline(IRequestHandler<TRequest, TResponse> inner, IEnumerable<IValidator<TRequest>> validators)
{
_inner = inner;
_validators = validators;
}
public TResponse Handle(TRequest message)
{
var failures = _validators
.Select(v => v.Validate(message))
.SelectMany(result => result.Errors)
.Where(f => f != null)
.ToList();
if (failures.Any())
throw new ValidationException(failures);
return _inner.Handle(request);
}
}
我现在如何为新版本执行此操作?如何设置使用哪个验证器?
答案 0 :(得分:15)
过程完全相同,您只需更改界面即可使用新的IPipelineBehavior<TRequest, TResponse>
界面。
public class ValidationBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
where TRequest : IRequest<TResponse>
{
private readonly IEnumerable<IValidator<TRequest>> _validators;
public ValidationBehavior(IEnumerable<IValidator<TRequest>> validators)
{
_validators = validators;
}
public Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next)
{
var context = new ValidationContext(request);
var failures = _validators
.Select(v => v.Validate(context))
.SelectMany(result => result.Errors)
.Where(f => f != null)
.ToList();
if (failures.Count != 0)
{
throw new ValidationException(failures);
}
return next();
}
}
对于验证器,您应该在内置容器中将所有验证器注册为IValidator<TRequest>
,以便将它们注入到行为中。如果您不想逐个注册,我建议您查看带有程序集扫描功能的优秀Scrutor library。通过这种方式,它可以自己找到验证器。
此外,使用新系统,您不再使用装饰器模式,只需在容器中注册您的通用行为,MediatR将自动选择它。它可能看起来像:
var services = new ServiceCollection();
services.AddMediatR(typeof(Program));
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));
var provider = services.BuildServiceProvider();
答案 1 :(得分:0)
我已经将.net核心集成打包到nuget中,可以随时使用它: https://www.nuget.org/packages/MediatR.Extensions.FluentValidation.AspNetCore
只需插入配置部分:
services.AddFluentValidation(new[] {typeof(GenerateInvoiceHandler).GetTypeInfo().Assembly});
答案 2 :(得分:0)
在新版本 (MediatR (>= 9.0.0)) 上,您可以执行以下操作:
public class ValidationBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> where TRequest : IRequest<TResponse>
{
private readonly IEnumerable<IValidator<TRequest>> _validators;
public ValidationBehavior(IEnumerable<IValidator<TRequest>> validators)
{
_validators = validators;
}
public Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
{
var context = new ValidationContext<TRequest>(request);
var failures = _validators
.Select(v => v.Validate(context))
.SelectMany(result => result.Errors)
.Where(f => f != null)
.ToList();
if (failures.Count != 0)
{
throw new ValidationException(failures);
}
return next();
}
}
记得在以前的版本中添加 var context = new ValidationContext<TRequest>(request);
,比如 FluentApi 8.0 或以下它使用了类似这样的东西 var context = new ValidationContext(request);
用于在Asp.Net Core中的IServiceCollection下注册,代码如下:
services.AddMediatR(Assembly.GetExecutingAssembly());
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));
希望对你有帮助!