RuleForEach - 需要访问项目的索引

RuleForEach - need access to item's index

考虑这个简化的代码:

public class Request
{
    public List<Selection> Selections { get; set; }
}

public class Selection
{
    public decimal Price { get; set; }
}

public class RequestValidator(): AbstractValidator<Request>
{
    public RequestValidator()
    {
        RuleForEach(x => x.Selections).SetValidator(new SelectionValidator());
    }
}

public class SelectionValidator : AbstractValidator<Selection>
{
    public SelectionValidator()
    {
        RuleFor(x => x.Price).NotEqual(0); 
    }
}

如果我有一个 Selection 项目且 Price 等于 0,我会收到错误消息: 'Price' must not be equal to '0'.

我缺少的是对集合中哪个元素有此错误的引用。

调试时我可以清楚地看到 Error.PropertyName 设置为 Selections[0].Price,但格式化的名称缺少对项目的引用。

有没有办法正确格式化 属性 全名?也许通过使用 .WithMessage() 但它似乎不起作用。

为了清楚起见,我的目标是让嵌套项的错误看起来像这样: <CollectionPropertyName>[<index>].<PropertyName> <error text>。前任。 Selectons[0].Price must not be equal to 0

可以覆盖Validate + ValidateAsync方法修改结果:

public abstract class ValidatorWithFullIndexerPath<T> : AbstractValidator<T>
{
    public override ValidationResult Validate(ValidationContext<T> context)
    {
        var result = base.Validate(context);
        FixIndexedPropertyErrorMessage(result);

        return result;
    }
    public override async Task<ValidationResult> ValidateAsync(ValidationContext<T> context, CancellationToken cancellation = default(CancellationToken))
    {
        var result = await base.ValidateAsync(context, cancellation);
        FixIndexedPropertyErrorMessage(result);

        return result;
    }

    protected void FixIndexedPropertyErrorMessage(ValidationResult result)
    {
        if (result.Errors?.Any() ?? false)
        {
            foreach (var error in result.Errors)
            {
                // check if 
                if (Regex.IsMatch(error.PropertyName, @"\[\d+\]") &&
                    error.FormattedMessagePlaceholderValues.TryGetValue("PropertyName", out var propertyName))
                {
                    // replace PropertyName with its full path
                    error.ErrorMessage = error.ErrorMessage
                        .Replace($"'{propertyName}'", $"'{error.PropertyName}'");
                }
            }
        }
    }
}

并且,更新 RequestValidator 和任何其他需要完整路径的 类:

public class RequestValidator : ValidatorWithFullIndexerPath<Request>

FluentValidation 8.1 包含一个新方法 OverrideIndexer() 来支持这个: