如何在MediatR验证行为中返回对应类型的Result失败实例
基于Result模式的MediatR ValidationBehavior通用失败返回实现
问题背景
在结合FluentValidation与MediatR实现ValidationBehavior时,要求返回Result或Result<TValue>类型结果。由于ValidationBehavior的泛型约束为TResponse: Result,仅能在运行时确定TResponse的具体类型,当验证失败时,直接返回非泛型Result.Failure并强制转换为TResponse会抛出类型转换异常(比如InsertPersonCommand需要返回Result<Guid>时,无法将非泛型Result转为泛型Result<Guid>)。需要实现通用方案,根据TResponse类型返回对应失败实例:
- 若
TResponse为泛型Result<TValue>,返回Result.Failure<TValue>(error) - 若为非泛型
Result,返回Result.Failure(error)
现有代码定义
基类Result
public class Result { protected internal Result(bool isSuccess, Error error){...} public Error Error { get; } public bool IsFailure => !IsSuccess; public bool IsSuccess { get; } // 静态创建Success和Failure结果的方法... // 示例: public static Result<TValue> Failure<TValue>(Error error) => error.ToResult<TValue>(); // 补充非泛型Failure方法(若之前未实现) public static Result Failure(Error error) => new Result(false, error); }
泛型Result
public class Result<TValue> : Result { private readonly TValue? _value; protected internal Result(TValue? value, bool isSuccess, Error error) : base(isSuccess, error) { _value = value; } public TValue Value => IsSuccess ? _value! : throw new InvalidOperationException("The value of a failure result can't be accessed."); }
ValidationBehavior定义
public class ValidationBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> where TRequest : IBaseRequest where TResponse : Result { // 注入验证器提供者,比如IValidatorFactory或IValidator<TRequest> private readonly IValidatorFactory _validatorFactory; public ValidationBehavior(IValidatorFactory validatorFactory) { _validatorFactory = validatorFactory; } }
解决方案:修改Handle方法实现类型适配
通过反射判断TResponse的类型,动态调用对应的Failure方法生成匹配类型的失败结果,避免强制转换异常:
public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken) { // 获取验证器并执行验证 var validator = _validatorFactory.GetValidator<TRequest>(); var validationResult = await validator.ValidateAsync(request, cancellationToken); if (!validationResult.IsValid) { var errors = CreateErrorsFromValidationFailures(validationResult.Errors); // 生成匹配TResponse类型的失败Result return CreateTypedFailureResult(errors); } return await next(); } private TResponse CreateTypedFailureResult(Error error) { var responseType = typeof(TResponse); // 判断是否为泛型Result<TValue>类型 if (responseType.IsGenericType && responseType.GetGenericTypeDefinition() == typeof(Result<>)) { // 获取泛型参数TValue var valueType = responseType.GetGenericArguments()[0]; // 调用Result.Failure<TValue>静态方法 var failureMethod = typeof(Result) .GetMethod(nameof(Result.Failure), new[] { typeof(Error) })! .MakeGenericMethod(valueType); var result = failureMethod.Invoke(null, new object[] { error })!; return (TResponse)result; } // 非泛型Result类型 else { var result = Result.Failure(error); return (TResponse)result; } } // 辅助方法:将FluentValidation的ValidationFailure转换为自定义Error类型 private Error CreateErrorsFromValidationFailures(IEnumerable<ValidationFailure> validationFailures) { // 实现转换逻辑,比如合并错误信息为自定义Error对象 var errorMessages = validationFailures.Select(f => f.ErrorMessage); return new Error("Validation.Failed", string.Join("; ", errorMessages)); }
说明
- 反射逻辑仅在验证失败时触发,对性能影响极小
- 需确保
Result类实现了非泛型的Failure方法(若之前未定义) - 若需要优化反射性能,可提前缓存泛型方法的委托(比如使用静态字典存储已解析的方法委托)
内容的提问来源于stack exchange,提问作者user7329164
相关产品推荐
相关产品推荐

