FluentValidation 将有效结果设置为自定义 属性
FluentValidation Set Valid Result to a Custom Property
我正在验证文件导入的内容,每行都有一个 IsValid
属性。
public class Header
{
public int LineNumber { get; set; }
public string Property1 { get; set; }
public string Property2 { get; set; }
public bool IsValid { get; set; }
}
public class Detail
{
public int LineNumber { get; set; }
public string Property1 { get; set; }
public string Property2 { get; set; }
public string Property3 { get; set; }
public bool IsValid { get; set; }
}
public class Trailer
{
public int LineNumber { get; set; }
public string Property1 { get; set; }
public bool IsValid { get; set; }
}
public class ImportFile
{
public Header Header { get; set; }
public List<Detail> Details { get; set; }
public Trailer Trailer { get; set; }
}
我的验证器看起来有点像:
public class DetailValidator : AbstractValidator<Detail>
{
public DetailValidator()
{
RuleFor(d => d.Property1)
.Cascade(CascadeMode.Stop)
.NotEmpty()
.WithState(d => d.LineNumber)
.Length(3)
.WithState(d => d.LineNumber);
RuleFor(d => d.Property2)
.Cascade(CascadeMode.Stop)
.NotEmpty()
.WithState(d => d.LineNumber)
.MaximumLength(50)
.WithState(d => d.LineNumber);
...
}
}
public class ImportFileValidator : AbstractValidator<ImportFile>
{
public ImportFileValidator()
{
RuleFor(f => f.Header)
.SetValidator(new HeaderValidator());
RuleForEach(f => f.Details)
.SetValidator(new DetailsValidator());
...
}
}
调用验证后,我想根据以下结果设置文件每一行的 IsValid
属性(无论是 header、详细信息还是预告片)验证。
现在可能的是,因为我正在使用 WithState
来存储 LineNumber
,我可以将 ValidationResult
与 ImportFile
实例进行匹配以设置每个行的有效性如下:
ImportFile file = // parsed file content
var result = new ImportFileValidator().Validate(file);
foreach (var detail in file.Details)
{
var error = result.Errors.FirstOrDefault(e =>
Convert.ToInt32(e.CustomState) == detail.LineNumber);
detail.IsValid = error == null;
}
而且我还必须检查 header 和预告片。
有什么方法可以在验证器中执行此操作?我正在尝试浏览 FluentValidation 的文档,但我似乎无法在那里找到我需要的东西。
当我探索 FluentValidation 中的可用方法时,我看到了 OnFailure
和 OnAnyFailure
方法。这些方法可能对我需要做的事情有很好的帮助,但问题是它们在 10.3.0
后已经过时,并将在 11
版本中删除。他们建议改用自定义验证器。
Header、详细信息和预告片摘要验证器保持原样。
我为这 3 个创建了自定义验证程序扩展。
每个扩展方法都会创建相应验证器的实例并执行它。我可以将它们设为通用的 header、细节和预告片,因为它们会做同样的事情,将 IsValid 属性 设置为验证结果。
public static IRuleBuilderOptionsConditions<ImportFile, T> IsHeaderValid<T>(this IRuleBuilder<ImportFile, T> ruleBuilder)
where T : Header
{
return builder.Custom((header, context) =>
{
// Create the Header Abstract Validator Instance
var validator = new HeaderValidator();
var result = validator.Validate(Header);
header.IsValid = result.IsValid;
// Pass the errors to the context
result.Errors.ForEach(context.AddFailure);
}
}
- 我不得不更改 ImportFileValidator 以调用自定义验证器,而不是使用 setvalidator。
ImportFileValidator 如下所示:
public class ImportFileValidator : AbstractValidator<ImportFile>
{
public ImportFileValidator()
{
RuleFor(f => f.Header)
.IsHeaderValid();
RuleForEach(f => f.Details)
.IsDetailValid();
...
}
}
这几乎就是我能够设置 IsValid
属性 的方式,而无需进行我最初在问题中所做的匹配。
我正在验证文件导入的内容,每行都有一个 IsValid
属性。
public class Header
{
public int LineNumber { get; set; }
public string Property1 { get; set; }
public string Property2 { get; set; }
public bool IsValid { get; set; }
}
public class Detail
{
public int LineNumber { get; set; }
public string Property1 { get; set; }
public string Property2 { get; set; }
public string Property3 { get; set; }
public bool IsValid { get; set; }
}
public class Trailer
{
public int LineNumber { get; set; }
public string Property1 { get; set; }
public bool IsValid { get; set; }
}
public class ImportFile
{
public Header Header { get; set; }
public List<Detail> Details { get; set; }
public Trailer Trailer { get; set; }
}
我的验证器看起来有点像:
public class DetailValidator : AbstractValidator<Detail>
{
public DetailValidator()
{
RuleFor(d => d.Property1)
.Cascade(CascadeMode.Stop)
.NotEmpty()
.WithState(d => d.LineNumber)
.Length(3)
.WithState(d => d.LineNumber);
RuleFor(d => d.Property2)
.Cascade(CascadeMode.Stop)
.NotEmpty()
.WithState(d => d.LineNumber)
.MaximumLength(50)
.WithState(d => d.LineNumber);
...
}
}
public class ImportFileValidator : AbstractValidator<ImportFile>
{
public ImportFileValidator()
{
RuleFor(f => f.Header)
.SetValidator(new HeaderValidator());
RuleForEach(f => f.Details)
.SetValidator(new DetailsValidator());
...
}
}
调用验证后,我想根据以下结果设置文件每一行的 IsValid
属性(无论是 header、详细信息还是预告片)验证。
现在可能的是,因为我正在使用 WithState
来存储 LineNumber
,我可以将 ValidationResult
与 ImportFile
实例进行匹配以设置每个行的有效性如下:
ImportFile file = // parsed file content
var result = new ImportFileValidator().Validate(file);
foreach (var detail in file.Details)
{
var error = result.Errors.FirstOrDefault(e =>
Convert.ToInt32(e.CustomState) == detail.LineNumber);
detail.IsValid = error == null;
}
而且我还必须检查 header 和预告片。
有什么方法可以在验证器中执行此操作?我正在尝试浏览 FluentValidation 的文档,但我似乎无法在那里找到我需要的东西。
当我探索 FluentValidation 中的可用方法时,我看到了 OnFailure
和 OnAnyFailure
方法。这些方法可能对我需要做的事情有很好的帮助,但问题是它们在 10.3.0
后已经过时,并将在 11
版本中删除。他们建议改用自定义验证器。
Header、详细信息和预告片摘要验证器保持原样。
我为这 3 个创建了自定义验证程序扩展。
每个扩展方法都会创建相应验证器的实例并执行它。我可以将它们设为通用的 header、细节和预告片,因为它们会做同样的事情,将 IsValid 属性 设置为验证结果。
public static IRuleBuilderOptionsConditions<ImportFile, T> IsHeaderValid<T>(this IRuleBuilder<ImportFile, T> ruleBuilder)
where T : Header
{
return builder.Custom((header, context) =>
{
// Create the Header Abstract Validator Instance
var validator = new HeaderValidator();
var result = validator.Validate(Header);
header.IsValid = result.IsValid;
// Pass the errors to the context
result.Errors.ForEach(context.AddFailure);
}
}
- 我不得不更改 ImportFileValidator 以调用自定义验证器,而不是使用 setvalidator。
ImportFileValidator 如下所示:
public class ImportFileValidator : AbstractValidator<ImportFile>
{
public ImportFileValidator()
{
RuleFor(f => f.Header)
.IsHeaderValid();
RuleForEach(f => f.Details)
.IsDetailValid();
...
}
}
这几乎就是我能够设置 IsValid
属性 的方式,而无需进行我最初在问题中所做的匹配。