C# 空对象的 FluentValidation 规则
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 
原文地址: http://stackoverflow.com/questions/17095791/
Warning: these are provided under cc-by-sa 4.0 license.  You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
FluentValidation rule for null object
提问by Bern
I've been trying to work out how to create a FluentValidation rule that checks if the instance of an object it's validating is not null, prior to validating it's properties.
我一直在努力研究如何创建一个 FluentValidation 规则,在验证它的属性之前检查它正在验证的对象的实例是否不为空。
I'd rather encapsulate this null validation in the Validator rather then doing it in the calling code.
我宁愿将此空验证封装在 Validator 中,而不是在调用代码中进行。
See example code below with comments where the required logic is needed:
请参阅下面的示例代码,其中包含需要所需逻辑的注释:
namespace MyNamespace
{
    using FluentValidation;
    public class Customer
    {
        public string Surname { get; set; }
    }
    public class CustomerValidator: AbstractValidator<Customer> 
    {
        public CustomerValidator() 
        {
            // Rule to check the customer instance is not null.
            // Don't continue validating.
            RuleFor(c => c.Surname).NotEmpty();
        }
    }
    public class MyClass
    {
        public void DoCustomerWork(int id)
        {
            var customer = GetCustomer(id);
            var validator = new CustomerValidator();
            var results = validator.Validate(customer);
            var validationSucceeded = results.IsValid;
        }
        public Customer GetCustomer(int id)
        {
            return null;
        }
    }
}
So my question is how do I check in the CustomerValidator() constructor that the current instance of customer is not nulland abort further rule processing if it is null?
所以我的问题是如何在 CustomerValidator() 构造函数中检查 customer 的当前实例不为 null并在它为 null 时中止进一步的规则处理?
Thanks in advance.
提前致谢。
采纳答案by Matthew
You should be able to override the Validatemethod in your CustomerValidatorclass.
您应该能够覆盖类中的Validate方法CustomerValidator。
public class CustomerValidator: AbstractValidator<Customer> 
{
    // constructor...
    public override ValidationResult Validate(Customer instance)
    {
        return instance == null 
            ? new ValidationResult(new [] { new ValidationFailure("Customer", "Customer cannot be null") }) 
            : base.Validate(instance);
    }
}
回答by Patryk ?wiek
I can't really test that right now, but you can either try to override Validate, or include the rules in the Whenblock:
我现在无法真正测试它,但是您可以尝试覆盖Validate,或者在When块中包含规则:
public CustomerValidator()
{
     When(x => x != null, () => {
         RuleFor(x => x.Surname).NotEmpty();
         //etc.
     });
}
回答by chrispr
I inherited from the fluent AbstractValidator and created a NullReferenceAbstractValidator class instead:
我继承了 fluent AbstractValidator 并创建了一个 NullReferenceAbstractValidator 类:
public class NullReferenceAbstractValidator<T> : AbstractValidator<T>
{
    public override ValidationResult Validate(T instance)
    {
        return instance == null
            ? new ValidationResult(new[] { new ValidationFailure(instance.ToString(), "response cannot be null","Error") })
            : base.Validate(instance);
    }
}
and then inherited from that class with each validator that needed a null reference check:
然后从该类继承每个需要空引用检查的验证器:
public class UserValidator : NullReferenceAbstractValidator<User>
回答by Lee Campbell
As the above solutions didn't work for me (FluentValidation, Version=6.2.1.0 for Net45), I am posting what I did.
This is just a simple replacement/wrapper for ValidateAndThrowextension method.
由于上述解决方案对我不起作用(FluentValidation,Net45 的版本 = 6.2.1.0),我发布了我所做的。这只是ValidateAndThrow扩展方法的简单替换/包装器。
public static class ValidatorExtensions
{
    public static void ValidateAndThrowNotNull<T>(this IValidator<T> validator, T instance)
    {
        if (instance == null)
        {
            var validationResult = new ValidationResult(new[] { new ValidationFailure("", "Instance cannot be null") });
            throw new ValidationException(validationResult.Errors);
        }
        validator.ValidateAndThrow(instance);
    }
}
回答by Elmar
For those using version >6.2.1 you need to override this signature instead, in order to achieve the same as @chrispr:
对于那些使用版本 >6.2.1 的用户,您需要覆盖此签名,以实现与 @chrispr 相同的效果:
public override ValidationResult Validate(ValidationContext<T> context)
{
    return (context.InstanceToValidate == null) 
        ? new ValidationResult(new[] { new ValidationFailure("Property", "Error Message") })
        : base.Validate(context);       
}
回答by Trevor
Use the Cascade mode.
使用级联模式。
Here is the example from the documentation.
这是文档中的示例。
RuleFor(x => x.Surname).Cascade(CascadeMode.StopOnFirstFailure).NotNull().NotEqual("foo");
Also from the documentation:
同样来自文档:
If the NotNull validator fails then the NotEqual validator will not be executed. This is particularly useful if you have a complex chain where each validator depends on the previous validator to succeed.
如果 NotNull 验证器失败,则不会执行 NotEqual 验证器。如果您有一个复杂的链,其中每个验证器都依赖于前一个验证器才能成功,这将特别有用。
回答by CreativeManix
Override EnsureInstanceNotNull as below
如下覆盖EnsureInstanceNotNull
protected override void EnsureInstanceNotNull(object instanceToValidate)
{
    if(instanceToValidate==null)
      throw new ValidationException("Customer can not be null");
}
回答by user7617828
By means of Custom(). It can be also very helpful when validation of another field is based on validation of your current field.
通过自定义()。当另一个字段的验证基于当前字段的验证时,它也非常有用。
ruleBuilder.Custom((obj, context) =>
        {
            if (obj != null)
            {
                var propertyName = <field where should be validation>;
                context.AddFailure(propertyName, "'Your field name' Your validation message.");
            }
        });
回答by camainc
This is an older post, but want to update the answers to include the following from the FluentValidation documentation:
这是一篇较旧的帖子,但想要更新答案以包含 FluentValidation 文档中的以下内容:
Using PreValidate
使用预验证
If you need to run specific code every time a validator is invoked, you can do this by overriding the PreValidate method. This method takes a ValidationContext as well as a ValidationResult, which you can use to customise the validation process.
如果每次调用验证器时都需要运行特定代码,则可以通过覆盖 PreValidate 方法来实现。此方法采用 ValidationContext 和 ValidationResult,您可以使用它们来自定义验证过程。
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("", "Please ensure a model was supplied."));
      return false;
    }
    return true;
  }
}

