异步验证

在某些情况下 我们可能需要定义异步的规则 比如说我们可能会使用一些外部的API来进行验证。 By default, FluentValidation 允许我们使用 MustAsyncCustomAsync 来定义异步规则,也可以用 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一起配合使用,则它们将始终同步运行。

回调 Callbacks

在8.0之后我们可以想要在验证错误的时候做一些事情,还可以使用OnAnyFailure 和 OnFailure 回调来执行

OnAnyFailure

某个属性的任意错误

RuleFor(x => x.Surname).NotNull().Must(surname => surname != null && surname.Length <= 200)
  .OnAnyFailure(x => {
    Console.WriteLine("至少有一个验证规则错了");
  })

OnFailure

某个属性下面某个验证规则的错

RuleFor(x => x.Surname).NotNull().OnFailure(x => Console.WriteLine("Nonull failed"))
  .Must(surname => surname != null && surname.Length <= 200)
  .OnFailure(x => Console.WriteLine("Must 失败了"));

前置验证 PreValidate

如果需要在每次调用验证器时运行特定代码,则可以通过重写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;
  }
}

上下文数据 Root Context Data

在某些情况下,我们可能会希望把自己的数据传递到验证管道当中,这样的话自定义属性验证器就可以获取到它的值,从而进行一些想要的操作。因为验证器是无状态的,如果某些情况下我们要跟据环境来做一些变化的话。这个上下文数据是非常有用的。

把值传递到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");
  }
});
最近更新的
...