web-dev-qa-db-ja.com

nullオブジェクトのFluentValidationルール

プロパティを検証する前に、検証するオブジェクトのインスタンスがnullでないかどうかをチェックするFluentValidationルールを作成する方法を模索しています。

このnull検証は、呼び出しコードで行うのではなく、Validatorでカプセル化します。

必要なロジックが必要なコメントを含む以下のサンプルコードを参照してください。

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;
        }
    }
}

したがって、私の質問はCustomerValidator()コンストラクタで、顧客の現在のインスタンスがnullでないことをどのようにチェックするかおよびnullの場合、さらにルール処理を中止するですか?

前もって感謝します。

36
Bern

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);
    }
}
31
Matthew

今は実際にはテストできませんが、Validateをオーバーライドするか、Whenブロックにルールを含めることができます。

public CustomerValidator()
{
     When(x => x != null, () => {
         RuleFor(x => x.Surname).NotEmpty();
         //etc.
     });
}
16
Patryk Ćwiek

バージョン> 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);       
}
6
Elmar

これは古い投稿ですが、FluentValidationのドキュメントから以下を含むように回答を更新したいと思います。

PreValidateを使用する

バリデーターが呼び出されるたびに特定のコードを実行する必要がある場合は、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;
  }
}

https://fluentvalidation.net/start#using-prevalidate

5
camainc

上記の解決策がうまくいかなかった(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);
    }
}
2
Lee Campbell

私は流暢な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);
    }
}

次に、null参照チェックを必要とする各バリデーターでそのクラスから継承しました。

public class UserValidator : NullReferenceAbstractValidator<User>
2
chrispr

カスケードモードを使用します。

documentation の例を次に示します。

RuleFor(x => x.Surname).Cascade(CascadeMode.StopOnFirstFailure).NotNull().NotEqual("foo");

また、ドキュメントから:

NotNullバリデーターが失敗した場合、NotEqualバリデーターは実行されません。これは、各バリデーターが成功するために前のバリデーターに依存している複雑なチェーンがある場合に特に役立ちます。

1
Trevor

Custom()を使用します。別のフィールドの検証が現在のフィールドの検証に基づいている場合にも非常に役立ちます。

ruleBuilder.Custom((obj, context) =>
        {
            if (obj != null)
            {
                var propertyName = <field where should be validation>;
                context.AddFailure(propertyName, "'Your field name' Your validation message.");
            }
        });
1
user7617828

以下のように、EnsureInstanceNotNullをオーバーライドします。

protected override void EnsureInstanceNotNull(object instanceToValidate)
{
    if(instanceToValidate==null)
      throw new ValidationException("Customer can not be null");
}
1
CreativeManix