替换为LangExt Result<T>后MediatR的ValidationBehavior未触发
我用LangExt库把所有异常替换成Result<T>后,遇到ValidationBehavior完全不触发的问题。之前当ValidationBehavior的签名是public class ValidationBehavior<TRequest, TResponse>(IEnumerable<IValidator<TRequest>> validators) : IPipelineBehavior<TRequest, TResponse> where TRequest : IRequest<TResponse>时能正常触发,现在需要调整注册方式让它重新生效,而且不想手动指定AbstractValidator类。
相关代码如下:
注册代码
builder.Services.AddValidatorsFromAssemblyContaining<Program>(); builder.Services.AddMediatR(configure => { configure.RegisterServicesFromAssemblyContaining<Program>(); configure.AddRequestPreProcessor(typeof(IRequestPreProcessor<>), typeof(LoggingBehavior<>)); configure.AddBehavior(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<>)); configure.AddBehavior(typeof(IPipelineBehavior<,>), typeof(MetricsBehavior<>)); });
ValidationBehavior实现代码
public class ValidationBehavior<TRequest, TResponse>(IEnumerable<IValidator<TRequest>> validators) : IPipelineBehavior<TRequest, Result<TResponse>> where TRequest : IRequest<Result<TResponse>> { public async Task<Result<TResponse>> Handle(TRequest request, RequestHandlerDelegate<Result<TResponse>> next, CancellationToken cancellationToken) { if (!validators.Any()) { return await next(); } var context = new ValidationContext<TRequest>(request); var validationResults = await Task.WhenAll(validators.Select(v => v.ValidateAsync(context, cancellationToken))); var failures = validationResults .Where(r => r.Errors.Count != 0) .SelectMany(r => r.Errors) .ToList(); if (failures.Count != 0) { return new Result<TResponse>(new ValidationException(failures)); } return await next(); } }
问题根源是你的MediatR注册代码和ValidationBehavior的泛型约束不匹配:现在的Behavior实现的是IPipelineBehavior<TRequest, Result<TResponse>>(返回类型固定为Result<TResponse>),但注册时还是用了通用的IPipelineBehavior<,>,导致MediatR无法将它匹配到对应的请求上。
修改注册代码中的AddBehavior部分,把ValidationBehavior的注册改成匹配其泛型约束的形式:
builder.Services.AddValidatorsFromAssemblyContaining<Program>(); builder.Services.AddMediatR(configure => { configure.RegisterServicesFromAssemblyContaining<Program>(); configure.AddRequestPreProcessor(typeof(IRequestPreProcessor<>), typeof(LoggingBehavior<>)); // 调整ValidationBehavior的注册,匹配它实现的IPipelineBehavior<TRequest, Result<TResponse>>开放泛型 configure.AddBehavior(typeof(IPipelineBehavior<, Result<>>), typeof(ValidationBehavior<,>)); configure.AddBehavior(typeof(IPipelineBehavior<,>), typeof(MetricsBehavior<>)); });
同时,确保你的请求类都实现了IRequest<Result<T>>接口(比如public class MyRequest : IRequest<Result<MyResponse>>),这样MediatR才能把ValidationBehavior关联到这些请求上。
另外,AddValidatorsFromAssemblyContaining<Program>()已经会自动扫描并注册程序集中所有继承自AbstractValidator<T>的验证器,所以不需要手动指定任何验证器类,只要请求对应的验证器存在,就会被注入到ValidationBehavior的validators参数中。
内容的提问来源于stack exchange,提问作者nop

