You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 08:35:58