在某些情况下 我们可能需要定义异步的规则 比如说我们可能会使用一些外部的API来进行验证。 By default, FluentValidation 允许我们使用 MustAsync
或 CustomAsync
来定义异步规则,也可以用 WhenAsync
来定义异步条件
如下的例子中,就使用了一个外部API的方式来检查这个用户是不是已经存在了。
public class CustomerValidator : AbstractValidator<Customer>
{
SomeExternalWebApiClient _client;
public CustomerValidator(SomeExternalWebApiClient client)
{
_client = client;
RuleFor(x => x.Id).MustAsync(async (id, cancellation) =>
{
bool exists = await _client.IdExists(id);
return !exists;
}).WithMessage("ID Must be unique");
}
}
使用验证器本质上是相同的,但是我们现在应该通过调用ValidateAsync来调用它:
var validator = new CustomerValidator(new SomeExternalWebApiClient());
var result = await validator.ValidateAsync(customer);
警告: 如果您的验证器包含异步验证器或异步条件,那么一定要始终在验证器上调用ValidateAsync而不是Validate,这一点很重要。 如果调用Validate,则异步规则将同步运行,这不是我们所期待的。
跟ASP.NET一起使用时,我们不应使用异步规则,因为ASP.NET的验证管道不是异步的。 如果我们将异步规则与ASP.NET一起配合使用,则它们将始终同步运行。
在8.0之后我们可以想要在验证错误的时候做一些事情,还可以使用OnAnyFailure 和 OnFailure 回调来执行
某个属性的任意错误
RuleFor(x => x.Surname).NotNull().Must(surname => surname != null && surname.Length <= 200)
.OnAnyFailure(x => {
Console.WriteLine("至少有一个验证规则错了");
})
某个属性下面某个验证规则的错
RuleFor(x => x.Surname).NotNull().OnFailure(x => Console.WriteLine("Nonull failed"))
.Must(surname => surname != null && surname.Length <= 200)
.OnFailure(x => Console.WriteLine("Must 失败了"));
如果需要在每次调用验证器时运行特定代码,则可以通过重写PreValidate方法来执行此操作。 此方法有两个参数ValidationContext以及ValidationResult,可用于自定义验证过程。
如果想验证继续进行下云,则该方法应返回true,否则应返回false。 我们对ValidationResult所做的任何修改都将返回给用户。
请注意,在FluentValidation对要验证的模型执行其标准的空检查之前,将调用此方法,因此,如果整个模型为空,则可以使用此方法生成错误,而不是在这种情况下依赖FluentValidation的标准行为(即 抛出异常):
public class MyValidator : AbstractValidator<Person>
{
public MyValidator()
{
RuleFor(x => x.Name).NotNull();
}
protected override bool PreValidate(ValidationContext<Person> context, ValidationResult result)
{
if (context.InstanceToValidate == null)
{
result.Errors.Add(new ValidationFailure("", "模型不能为空"));
return false;
}
return true;
}
}
在某些情况下,我们可能会希望把自己的数据传递到验证管道当中,这样的话自定义属性验证器就可以获取到它的值,从而进行一些想要的操作。因为验证器是无状态的,如果某些情况下我们要跟据环境来做一些变化的话。这个上下文数据是非常有用的。
把值传递到RootContextData
var instanceToValidate = new Person();
var context = new ValidationContext<Person>(person);
context.RootContextData["MyCustomData"] = "Test";
var validator = new PersonValidator();
validator.Validate(context);
获取数据进行判断
RuleFor(x => x.Surname).Custom((x, context) =>
{
if(context.RootContextData.ContainsKey("MyCustomData"))
{
context.AddFailure("My error message");
}
});