向 MediatR 行为管道添加验证?
Add validation to a MediatR behavior pipeline?
我正在使用 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);
}
}
现在如何为新版本执行此操作?如何设置要使用的验证器?
过程完全相同,您只需更改界面即可使用新的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();
}
}
对于验证器,您应该在 built-in 容器中将所有验证器注册为 IValidator<TRequest>
,以便将它们注入到行为中。如果你不想一一注册,我建议你看看Scrutor library这个自带汇编扫描功能的大佬。这样它会自己找到你的验证器。
此外,在新系统中,您不再使用装饰器模式,您只需在容器中注册您的通用行为,MediatR 会自动将其拾取。它可能看起来像:
var services = new ServiceCollection();
services.AddMediatR(typeof(Program));
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));
var provider = services.BuildServiceProvider();
我已经将 .net 核心集成打包到 nuget 中,请随意使用它:
https://www.nuget.org/packages/MediatR.Extensions.FluentValidation.AspNetCore
只需在配置部分插入:
services.AddFluentValidation(new[] {typeof(GenerateInvoiceHandler).GetTypeInfo().Assembly});
在新版本 (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();
}
}
记得在以前的版本如FluentApi 8.0或以下版本中添加var context = new ValidationContext<TRequest>(request);
它使用这样的东西var context = new ValidationContext(request);
用于在 IServiceCollection 下注册 Asp.Net 核心,代码如下:
services.AddMediatR(Assembly.GetExecutingAssembly());
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));
希望对您有所帮助!
我正在使用 ASP.NET Core、内置容器和支持 "behavior" pipelines:
的 MediatR 3public 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);
}
}
现在如何为新版本执行此操作?如何设置要使用的验证器?
过程完全相同,您只需更改界面即可使用新的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();
}
}
对于验证器,您应该在 built-in 容器中将所有验证器注册为 IValidator<TRequest>
,以便将它们注入到行为中。如果你不想一一注册,我建议你看看Scrutor library这个自带汇编扫描功能的大佬。这样它会自己找到你的验证器。
此外,在新系统中,您不再使用装饰器模式,您只需在容器中注册您的通用行为,MediatR 会自动将其拾取。它可能看起来像:
var services = new ServiceCollection();
services.AddMediatR(typeof(Program));
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));
var provider = services.BuildServiceProvider();
我已经将 .net 核心集成打包到 nuget 中,请随意使用它: https://www.nuget.org/packages/MediatR.Extensions.FluentValidation.AspNetCore
只需在配置部分插入:
services.AddFluentValidation(new[] {typeof(GenerateInvoiceHandler).GetTypeInfo().Assembly});
在新版本 (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();
}
}
记得在以前的版本如FluentApi 8.0或以下版本中添加var context = new ValidationContext<TRequest>(request);
它使用这样的东西var context = new ValidationContext(request);
用于在 IServiceCollection 下注册 Asp.Net 核心,代码如下:
services.AddMediatR(Assembly.GetExecutingAssembly());
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));
希望对您有所帮助!