我应该在 FluentValidation 中为集合创建一个新类型吗?

Abh*_*dha 4 .net c# asp.net validation fluentvalidation

我试图找出在 FluentValidation 中是否有可用的方法,它允许在根级别为验证器验证集合。

例如,如下所示,一个验证器可CustomerValidator用于一个类Customer。使用 FluentValidation;

public class CustomerValidator: AbstractValidator<Customer> {
  public CustomerValidator() {
    RuleFor(customer => customer.Surname).NotEmpty();
    RuleFor(customer => customer.Forename).NotEmpty().WithMessage("Please specify a first name");
    RuleFor(customer => customer.Discount).NotEqual(0).When(customer => customer.HasDiscount);
    RuleFor(customer => customer.Address).Length(20, 250);
    RuleFor(customer => customer.Postcode).Must(BeAValidPostcode).WithMessage("Please specify a valid postcode");
  }

  private bool BeAValidPostcode(string postcode) {
    // custom postcode validating logic goes here
  }
}

Customer customer = new Customer();
CustomerValidator validator = new CustomerValidator();
ValidationResult results = validator.Validate(customer);

bool validationSucceeded = results.IsValid;
IList<ValidationFailure> failures = results.Errors;
Run Code Online (Sandbox Code Playgroud)

问题是,如果我有一个List<Customer>并且我需要验证至少一个客户应该有Surname我如何验证列表。在 fluentvalidation 中是否有开箱即用的功能,此时,我可以考虑以下任一方式。你能建议什么是最好的方法吗?

1.循环迭代,然后为每个 Customer 调用 validate 方法。

 List<ValidationResult> listOfValidationErrors = List<ValidationResult>();
 // listCustomer is of type List<Customer>
 foreach (var customer in listCustomer)
 {
     CustomerValidator validator = new CustomerValidator();
     listOfValidationErrors.Add(validator.Validate(customer);
 }
Run Code Online (Sandbox Code Playgroud)

2.为Customer集合创建一个新的集合类CustomerCollection,然后创建一个验证器类CustomerCollectionValidator

    public class CustomerCollection
    {
        public List<Customer> ListOfCustomers { get; set; }

        public CustomerCollection(List<Customer> listOfCustomers )
        {
            this.ListOfCustomers = listOfCustomers ;
        }
    }
Run Code Online (Sandbox Code Playgroud)

然后是 Validator 类

public class CustomerCollectionValidator: CompositeValidator<CustomerCollection>
    {
        public CustomerCollectionValidator()
        {

            RuleFor(x => x.ListOfCustomers)
                    .Must(ShouldHaveOneSurName)
                    .WithMessage("Should have one Surname in list");

            RuleForEach(x => x.ListOfCustomers).SetValidator<CustomerValidator>();

        }

        public bool ShouldHaveOneSurName(List<Customer> lstCustomers)
        {
            if (lstCustomers== null)
            {
                return false;
            }
            return lstCustomers.Any(x => !String.IsNullOrWhiteSpace(x.SurName);
        }


    }
Run Code Online (Sandbox Code Playgroud)

Abh*_*dha 5

除了上述两种方法,Jeremy Skinner在这里提出了另一种方法,它使用继承自 AbstractValidator<List<Customer>>. 这不适用于原始代码,但 Jeremy 在此处提交了 6.3 版 Fluent Validation 源代码中的更改。

以下代码提供了对根级别集合进行验证的第三种方法。

public class CustomerCollectionValidator : AbstractValidator<List<Customer>> {
  public CustomerCollectionValidator() {
     RuleFor(list => list).SetCollectionValidator(new CustomerValidator());
  }
}
Run Code Online (Sandbox Code Playgroud)