根据其他属性验证属性的最佳做法

时间:2019-12-27 07:52:30

标签: c# fluentvalidation

想象一下,您有一个像这样的课程:

public enum Kind { Kind1, Kind2 }
public class MyForm
{
    public string Kind { get; set; }
    public ACustomClass1 Custom1 { get; set; }
    public ACustomClass2 Custom2 { get; set; }
}

并且您想在Custom1时用Custom1Validator验证Kind == Kind1(显然在Custom2时用Custom2Validator验证Kind == Kind2

继续使用8.6.0版的最佳方法是什么?

此刻,我已经这样做了(但是我觉得很尴尬):

public class MyFormValidator : AbstractValidator<MyForm>
{
    public MyFormValidator (IStringLocalizer<Strings> localizer, Custom1Validator validator1, Custom2Validator validator2)
    {            
        //validate Kind and then, in function of Kind, use correct validator
        RuleFor(x => x).Custom((f, context) => {
            if (!Enum.TryParse<Kind>(f.Kind, out var kind))
            {
                context.AddFailure(localizer["Invalid Kind"]);
                return;
            }
            switch (kind)
            {
                case Kind.Kind1:
                    if (f.Custom1 == null)
                    {
                        context.AddFailure(localizer["Invalid Kind"]);
                    }
                    else if (! validator1.Validate(f.Custom1, out var firstError))
                    {
                        context.AddFailure(firstError);
                    }
                    break;
                case Kind.Kind2:
                    if (f.Custom2 == null)
                    {
                        context.AddFailure(localizer["Invalid Kind"]);
                    }
                    else if (!validator2.Validate(f.Custom2, out var firstError))
                    {
                        context.AddFailure(firstError);
                    }
                    break;
            }
        });
    }
}

请注意,我使用的是带有依赖项注入的asp.net核心(这就是为什么IStringLocalizer出现在{1}和Custom2上而不能使用SetValidator的原因)

我想要的是类似的东西

RuleFor(x => x.Kind).NotEmpty().IsEnumName(typeof(Kind)).withMessage(_ => localizer["Invalid Kind"]);
RuleFor(x => x.Custom1).NotEmptyWhen(f => f.Kind == Kind.Custom1.ToString()).withMessage(_ => localizer["Invalid Kind"])
RuleFor(x => x.Custom1).SetValidator(validator1); //would be executed only when custom1 is not null

//与custom2相同

问题是我看不到如何编写NotEmptyWhen方法的代码

1 个答案:

答案 0 :(得分:1)

重组?

根据已发布代码段的外观,我假设MyForm在同一请求中永远不会具有填充的Custom1Custom2属性。因此,我建议您不要直接使用表示要验证的有效负载的模型,而不要拥有同时包含两种有效负载种类的父模型。这样一来,您就不会在需要时遇到这种检查种类的讨厌模式。

您的一个表单终结点接受Custom1,它具有关联的Custom1Validator。您的表单端点中的另一个端点接受Custom2,它具有关联的Custom2Validator。它们是分离的。您可以安全地更改其中一个而不影响另一个。

使用Fluent验证条件(何时/除非)

如果您对使用一个模型负责表示多个请求的有效负载(请不要这么做)感到厌烦,可以使用该库提供的When()方法。看看他们在conditional rules上的文档。