如何使用 MediatR 和 FluentValidation 实现通用 ValidationBehavion,以便 ValidationBehavion 仅在命令上触发

问题描述 投票:0回答:1
我正在使用 CQRS 并分离命令和查询,我创建了自定义接口,因此我希望我的 ValidationBehavion 仅在继承 IRequest

的自定义 ICommand 上触发,而不是在所有 IRequest 请求上触发。

为了分离命令和查询,我创建了自定义界面: (作为响应值,我使用 ErrorOr 库。但我认为不值得研究它,只需记住命令和查询总是有响应)

public interface ICommand<TResponse> : IRequest<ErrorOr<TResponse>> { } public interface IQuery<TResponse> : IRequest<ErrorOr<TResponse>> { }
public interface ICommandHandler<TCommand, TResponse> 
    : IRequestHandler<TCommand, ErrorOr<TResponse>>
    where TCommand : ICommand<TResponse>
{
}

public interface IQueryHandler<TQuery, TResponse>
    : IRequestHandler<TQuery, ErrorOr<TResponse>>
    where TQuery : IQuery<TResponse>
{
}
我知道一种标准方法,其中 IPipelineBehavior 会向任何请求者触发,然后我们检查该请求者是否有验证器:

public class ValidationBehavion<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> where TRequest : IRequest<TResponse> where TResponse : IErrorOr { private readonly IValidator<TRequest>? _validator; public ValidationBehavion(IValidator<TRequest>? validator = null) { _validator = validator; } public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken) { if(_validator is null) { return await next(); } var validationResult = await _validator.ValidateAsync(request); if (validationResult.IsValid) { return await next(); } var validationErrors = validationResult.Errors .ConvertAll(error => Errors.Wands.NotValid( error.PropertyName, error.ErrorMessage)); return (dynamic)validationErrors; } }
由于命令和查询是分离的,我想我可以指定 ICommand

而不是 IRequest 并重做 ValidationBehavion,如下所示:

public class ValidationBehavion<TRequest, TResponse> : IPipelineBehavior<TRequest, ErrorOr<TResponse>> where TRequest : ICommand<TResponse> { private readonly IValidator<TRequest> _validator; public ValidationBehavion(IValidator<TRequest> validator) { _validator = validator; } public async Task<ErrorOr<TResponse>> Handle(TRequest request, RequestHandlerDelegate<ErrorOr<TResponse>> next, CancellationToken cancellationToken) { var validationResult = await _validator.ValidateAsync(request); if (validationResult.IsValid) { return await next(); } var validationErrors = validationResult.Errors .ConvertAll(error => Errors.Wands.NotValid( error.PropertyName, error.ErrorMessage)); return validationErrors; } }
但是这个 IPipelineBehavior 根本不起作用,我不知道为什么。

asp.net-web-api cqrs fluentvalidation mediatr
1个回答
0
投票
您可能需要注册该行为。你的startup.cs应该看起来像这样:

public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddControllers(); services.AddMediatR(typeof(Startup)); services.AddValidatorsFromAssemblyContaining<Startup>(); // Register pipeline behaviors services.AddTransient(typeof(IPipelineBehavior<,>), typeof(LoggingBehavior<,>)); services.AddTransient(typeof(IPipelineBehavior<,>), typeof(AuthorizationBehavior<,>)); services.AddTransient(typeof(IPipelineBehavior<,>), typeof(PerformanceBehavior<,>)); services.AddTransient(typeof(IPipelineBehavior<,>), typeof(UnhandledExceptionBehavior<,>)); // Register request pre-processors and post-processors services.AddTransient(typeof(IRequestPreProcessor<>), typeof(ValidationPreProcessor<>)); services.AddTransient(typeof(IRequestPostProcessor<,>), typeof(LoggingPostProcessor<,>)); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); } }
您在这里有完整的教程:

https://argosco.io/using-ipipelinebehavior-irequestpreprocessor-and-irequestpostprocessor-in-a-net-core-api/net/

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.