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()
来支持这个:
考虑这个简化的代码:
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()
来支持这个: