例如,我有两个验证规则的验证器:
// Rule 1
RuleFor(o => o.Email).Must((email) => this.GetDataDataFromDB(email) != 0)
.WithMessage("User with provided Email was not found in database!");
// Rule 2
RuleFor(o => o.Email).Must((email) => this.GetDataDataFromDB(email) >= 1)
.WithMessage("There are multiple users with provided Email in database!");
正如您所看到的,使用相同的方法对数据库进行了两次调用。如何调用一次并将数据重用于其他规则?
显示错误消息时的另一个问题:
RuleFor(o => o.Email).Must((email) => this.GetDataDataFromDB(email) >= 1)
.WithMessage("There are multiple users with following Email '{0}' in database!",
(model, email) => { return email; });
有没有更好的方法来显示错误消息,而不是一直写这些lambda表达式来检索属性?就像在某处保存模型一样,然后再使用它。
简单易行的解决方案很不错!
答案 0 :(得分:4)
对于#1,恐怕没有办法做到这一点。验证器被设计为无状态,因此它们可以跨线程重用(事实上,强烈建议您将验证器实例创建为单例,因为实例化它们非常昂贵。默认情况下MVC集成执行此操作)。不要乱用静态字段,因为你会遇到线程问题。
(编辑:在这个特殊的简单情况下,您可以将规则合并为一次调用Must,但一般情况下您不能在规则之间共享状态)
对于#2,这取决于您正在使用的属性验证器。大多数属性验证器实际上允许您使用{PropertyValue}占位符,并且将自动插入该值。但是,在这种情况下,您使用的是“Must”验证器(PredicateValidator),它不支持占位符。
我在此处列出了哪些验证程序支持自定义占位符:https://github.com/JeremySkinner/FluentValidation/wiki/c.-Built-In-Validators
答案 1 :(得分:1)
第1部分
您希望将数据库调用从2减少到1,因此您需要使用字段来保存数据库调用结果,因为验证器规则代码实际上可以在"运行时&#34中工作; 即可。
验证员类:
public class MyValidator : Validator<UserAccount>
{
private int? _countOfExistingMails;
private string _currentEmail;
private object locker = new object();
public MyValidator()
{
CallEmailValidations();
// other rules...
}
}
这是邮件验证调用的单独方法。至于Must
将表达式作为参数,您可以使用它的参数传递方法名称:
public void CallEmailValidations()
{
RuleFor(o => o.Email).Must(x => EmailValidation(x, 0))
.WithMessage("User with provided Email was not found in database!");
RuleFor(o => o.Email).Must(x => EmailValidation(x, 1))
.WithMessage("There are multiple users with provided Email in database!");
}
验证方法的身体本身:
public bool EmailValidation(string email, int requiredCount)
{
var isValid = false;
lock(locker)
{
if (email != _currentEmail || _currentEmail == null)
{
_currentEmail = email;
_countOfExistingMails = (int)GetDataDataFromDB(email);
}
if (requiredCount == 0)
{
isValid = _countOfExistingMails != 0; // Rule 1
}
else if (requiredCount == 1)
{
isValid = _countOfExistingMails <= 1; // Rule 2
}
}
// Rule N...
return isValid;
}
更新的: 此代码有效,但更好的方法是在数据访问层方法中实现缓存。
第2部分
这是重写的规则:
RuleFor(o => o.Email).Must((email) => GetDataDataFromDB(email) >= 1)
.WithMessage("There are multiple users with following Email '{0}' in database!", m => m.Email)
当lambda表达式只需要一个参数时,那就是 参数可以隐式输入,C#3允许你省略 括号,所以它现在有这种形式
<强>陷阱:强>
不要将this
显式传递给lambda表达式。据我所知,它可能会导致性能问题。没有理由创建额外的闭包。
我想您在DataContext
方法中以某种形式使用GetDataDataFromDB
。所以你必须控制你的上下文的生命周期,因为验证器对象被实例化为单一的。