RuleForEach-需要访问项目的索引

时间:2019-01-09 21:28:59

标签: c# fluentvalidation

考虑以下简化代码:

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等于0的Price项目,我会收到错误消息: 'Price' must not be equal to '0'.

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

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

是否可以正确格式化完整的属性名称?也许使用.WithMessage(),但似乎不起作用。

Example of debug info

为了清楚起见,我的目标是使嵌套项目的错误如下所示: <CollectionPropertyName>[<index>].<PropertyName> <error text>。例如Selectons[0].Price must not be equal to 0

2 个答案:

答案 0 :(得分:1)

You can override the Validate + ValidateAsync method to modify the result:

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}'");
                }
            }
        }
    }
}

And, update RequestValidator and any other classes where full path is desired:

public class RequestValidator : ValidatorWithFullIndexerPath<Request>

答案 1 :(得分:0)

FluentValidation 8.1包含一个支持此功能的新方法OverrideIndexer()