我有一个域模型/实体,取决于它的填充方式需要以不同方式进行验证。假设我提出了3个验证器,如下所示:
public class Product1Validator : AbstractValidator<Ticket>
{
public Product1Validator()
{
RuleFor(ticket => ticket.Policy.PolicyNumber)
.NotEmpty()
.WithMessage("Policy Number is missing.");
RuleFor(ticket => ticket.Policy.ApplSignedInState)
.NotEmpty()
.WithMessage("Application Signed In State is missing or invalid.");
}
}
public class Product2Validator : AbstractValidator<Ticket>
{
public Product2Validator()
{
RuleFor(ticket => ticket.Policy.PolicyNumber)
.NotEmpty()
.WithMessage("Policy Number is missing.");
RuleFor(ticket => ticket.Policy.ApplSignedInState)
.NotEmpty()
.WithMessage("Application Signed In State is missing or invalid.");
}
}
public class Product3Validator : AbstractValidator<Ticket>
{
public Product3Validator()
{
RuleFor(ticket => ticket.Policy.PolicyNumber)
.NotEmpty()
.WithMessage("Policy Number is missing.");
RuleFor(ticket => ticket.Policy.ApplSignedInState)
.NotEmpty()
.WithMessage("Application Signed In State is missing or invalid.");
RuleFor(ticket => ticket.Policy.DistributionChannel)
.NotEmpty()
.WithMessage("Distribution Channel is missing.");
}
}
如何重构重复的RuleFor(s),以便它们只有一个并由不同的验证器共享?
谢谢你, 斯蒂芬
更新
我使用了Ouarzy的想法,但是当我编写代码来验证它不会编译时。
[TestMethod]
public void CanChainRules()
{
var ticket = new Ticket();
ticket.Policy = new Policy();
ticket.Policy.ApplSignedInState = "CA";
ticket.Policy.PolicyNumber = "";
ticket.Policy.DistributionChannel = null;
var val = new Product1Validator();
var result = val.Validate(ticket); //There is no Method 'Validate'
Assert.IsTrue(!result.IsValid);
Console.WriteLine(result.Errors.GetValidationText());
}
更新2
问题是新的复合验证器并没有从AbstractValidator继承,一旦我纠正它编译它,但它们似乎不起作用。
public class Product1Validator : AbstractValidator<Ticket>
{
public Product1Validator()
{
TicketValidator.Validate().Policy().ApplSignedState();
}
}
更新3
在对原始答案严厉批评并直接在GitHub上与Jeremy联系之后,我提出了以下建议:
class Program{
static void Main(string[] args){
var p = new Person();
var pv = new PersonValidator();
var vr = pv.Validate(p);
//Console.ReadKey();
}
}
class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime BirthDate { get; set; }
}
class PersonValidator : AbstractValidator<Person>
{
public PersonValidator()
{
CascadeMode = CascadeMode.Continue;
this.FirstName();
this.LastName();
}
}
static class Extensions
{
public static void FirstName(this AbstractValidator<Person> a)
{
a.RuleFor(b => b.FirstName).NotEmpty();
}
public static void LastName(this AbstractValidator<Person> a)
{
a.RuleFor(b => b.LastName).NotEmpty();
}
}
答案 0 :(得分:2)
在您的情况下,我可能会尝试使用所有规则为Ticket构建流畅的验证,然后为每个产品调用所需的验证。类似的东西:
public class TicketValidator : AbstractValidator<Ticket>
{
public TicketValidator Policy()
{
RuleFor(ticket => ticket.Policy.PolicyNumber)
.NotEmpty()
.WithMessage("Policy Number is missing.");
return this;
}
public TicketValidator ApplSignedState()
{
RuleFor(ticket => ticket.Policy.ApplSignedInState)
.NotEmpty()
.WithMessage("Application Signed In State is missing or invalid.");
return this;
}
public TicketValidator DistributionChannel()
{
RuleFor(ticket => ticket.Policy.DistributionChannel)
.NotEmpty()
.WithMessage("Distribution Channel is missing.");
return this;
}
public static TicketValidator Validate()
{
return new TicketValidator();
}
}
然后使用流利的语法为每个产品设置一个验证器:
public class Product1Validator
{
public Product1Validator()
{
TicketValidator.Validate().Policy().ApplSignedState();
}
}
public class Product2Validator
{
public Product2Validator()
{
TicketValidator.Validate().Policy().ApplSignedState();
}
}
public class Product3Validator
{
public Product3Validator()
{
TicketValidator.Validate().Policy().ApplSignedState().DistributionChannel();
}
}
我没有尝试编译此代码,但我希望您能看到这个想法。
希望它有所帮助。
答案 1 :(得分:1)
集中式扩展方法
我想在多种不同类型的对象中使用它们。
我通过创建集中式扩展方法来做到这一点。
一个简单的例子:
扩展方法
namespace FluentValidation
{
public static class LengthValidator
{
public static IRuleBuilderOptions<T, string>
CustomerIdLength<T>(this IRuleBuilder<T, string> ruleBuilder)
{
return ruleBuilder.Length<T>(1, 0);
}
}
}
使用
public class CreateCustomerValidator : AbstractValidator<CreateCustomerCommand>
{
public CreateCustomerValidator()
{
RuleFor(x => x.CustomerId).CustomerIdLength();
}
}
当类型化对象通过泛型传递时,它可以跨多个对象使用,而不仅仅是一个对象,即
public class UpdateCustomerValidator : AbstractValidator<UpdateCustomerCommand>