我正在开发的系统使用FluentValidation(v5.0.0.1)。
我想要做的是创建几个部分验证对象的验证器,然后根据当时的要求将其合并到其他验证器中。
例如,假设我的班级有姓名和地址。 (这不能像示例中那样分成单独的类)。
对于方案1,我只想验证名称,所以我写了一个名称验证器类。
对于方案2,我只想验证地址,所以我写了一个地址验证器类。
对于方案3,我想验证名称和地址,因此我想编写一个新的验证器类,它调用名称验证器,然后调用地址验证器。
我不想在不同的地方重复代码,这就是我希望它们分开的原因。我也不想使用When运算符,因为无法从对象的内容中确定何时。
我知道我可以调用SetValidator,但是如何编写调用?
RuleFor(j=>j).SetValidator(new NameValidator());
RuleFor(j=>j).SetValidator(new AddressValidator());
不起作用。
答案 0 :(得分:1)
我将用这个例子解释解决方案。我将验证此联系人实体:
public class Contact
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public string PostalCode { get; set; }
}
要求是验证FirstName和LastName,然后验证Address1,Address2,City,PostalCode,并且可以在其他实体中重用我们的验证器。
创建接口以定义特定实体的内容。
public interface IAmPerson
{
string FirstName { get; set; }
string LastName { get; set; }
}
public interface IHaveAddress
{
string Address1 { get; set; }
string Address2 { get; set; }
string City { get; set; }
string PostalCode { get; set; }
}
现在Contact实体必须实现两个接口:
public class Contact : IAmPerson, IHaveAddress
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public string PostalCode { get; set; }
}
然后,为IAmPerson实体创建第一个验证器
public class PersonValidator : AbstractValidator<IAmPerson>
{
public PersonValidator()
{
RuleFor(data => data.FirstName).Length(3, 50).WithMessage("Invalid firstName");
RuleFor(data => data.LastName).Length(3, 50).WithMessage("Invalid LastName");
}
}
IHaveAddress实体的第二个
public class AddressValidator : AbstractValidator<IHaveAddress>
{
public AddressValidator()
{
RuleFor(data => data.Address1).NotNull().NotEmpty().WithMessage("Invalid address1");
RuleFor(data => data.Address2).NotNull().NotEmpty().WithMessage("Invalid address2");
RuleFor(data => data.City).NotNull().NotEmpty().WithMessage("Invalid City");
RuleFor(data => data.PostalCode).NotNull().NotEmpty().WithMessage("Invalid PostalCode");
}
}
使用自定义验证器的方法
public class ContactValidator: AbstractValidator<Contact>
{
public ContactValidator()
{
RuleFor(contact => contact).SetValidator(new PersonValidator());
RuleFor(contact => contact).SetValidator(new AddressValidator());
}
}
现在,您可以使用验证器验证任何其他实体中的人员数据或地址数据。您需要做的独特之处是在要验证的实体中实现特定的接口。
<强> [UPDATE] 强>
您可以通过添加扩展程序来提高代码的可读性
public static class ValidatorExtensions
{
public static IRuleBuilderOptions<T, IHaveAddress> MustHaveAValidAddress<T>(this IRuleBuilder<T, IHaveAddress> ruleBuilder)
{
return ruleBuilder.SetValidator(new AddressValidator());
}
public static IRuleBuilderOptions<T, IAmPerson> MustBeAValidPerson<T>(this IRuleBuilder<T, IAmPerson> ruleBuilder)
{
return ruleBuilder.SetValidator(new PersonValidator());
}
}
这是使用我刚添加的扩展方法的最终结果:
RuleFor(contact => contact).MustBeAValidPerson();
RuleFor(contact => contact).MustHaveAValidAddress();
答案 1 :(得分:0)
如果您使用与您相同类型的验证器,它将仅使用该类型上设置的最后一个验证器(在您的情况下为AddressValidator
)。您可以创建一些方法来封装验证并使用Must
。
请注意,您将无法在这些不同的验证中重复使用相同的错误代码或错误消息。
public static class Validations
{
public static bool ValidateName(string name)
{
return name != null; //Or any other validation
}
public static bool ValidateAddress(string address)
{
return !string.IsNullOrEmpty(address); //Or any other validation
}
}
情景1
RuleFor(j=>j.Name).Must(Validations.ValidateName);
情景2
RuleFor(j=>j.Address).Must(Validations.ValidateAddress);
情景3
RuleFor(j=>j.Name).Must(Validations.ValidateName);
RuleFor(j=>j.Address).Must(Validations.ValidateAddress);