子属性的选择性验证-MVC中的Fluent验证

本文关键字:验证 -MVC Fluent 中的 选择性 属性 | 更新日期: 2023-09-27 18:21:21

我使用Fluent Validation和Ninject.Web.Mvc.FluentValidation库来自动连接我的所有验证器(并使用依赖项注入来创建验证器)。

我创建了以下模型:

public class Parent
{
    public string Name { get; set; }
    public Child Child1 { get; set; }
    public Child Child2 { get; set; }
}
public class Child
{
    public string ChildProperty { get; set; }
}

具有以下验证器:

public class ParentValidator : AbstractValidator<Parent>
{
    public ParentValidator()
    {
         RuleFor(model => model.Name).NotEmpty();
         RuleFor(model => model.Child1).SetValidator(new ChildValidator());
    }
}
public class ChildValidator : AbstractValidator<Child>
{
    public ChildValidator()
    {
        RuleFor(model => model.ChildProperty).NotEmpty();
    }
}

我的看法:

@model Parent
@using(Html.BeginForm())
{
    @Html.EditorFor(model => model.Name)
    @Html.ValidationMessageFor(model => model.Name)
    @Html.EditorFor(model => model.Child1)
    @Html.EditorFor(model => model.Child2)
    <input type="submit" value="Save" />
}
@model Child
@Html.EditorFor(model => model.ChildProperty)
@Html.EditorFor(model => model.ChildProperty)

我试图实现的是拥有一个具有两个子属性的父模型。Child1的属性是必需的,但Child2的属性是可选的。这在正常情况下很好,但当我使用Ninject模块自动连接验证器时,它会检测到Child类有一个验证器类型,并连接Parent上的所有Child属性。

在不去掉Ninject模块的情况下,有什么方法可以防止这种情况发生吗?

子属性的选择性验证-MVC中的Fluent验证

由于自动连线无法有条件地了解在模型绑定期间何时应用ChildValidator类,因此似乎有几个替代方案:

  1. 确定子视图模型的重用是否如此重要面对这种情况,如果Child对象不是很复杂,并且单独使用Child对象的视图不超过两个,我可能会将子视图折叠到该视图的父视图中。我总是有点不愿意对视图模型过于枯燥,因为在我的经验中,页面结构往往会随着时间的推移而不同
  2. 清除Child2的ModelState错误。从这里,您可以完全控制Child2的验证,包括在这个独特的上下文中为Child2提供一个单独的验证器,并手动应用它。这也是我喜欢FluentValidation的原因之一,它能够在不同的上下文中将不同的验证逻辑应用于同一视图模型,而不是数据注释

自动连线的值(即它排除的所有额外代码)将排除在这种情况下关闭它的选项

您忘记将验证器设置为第二个子属性:

public class ParentValidator : AbstractValidator<Parent>
{
    public ParentValidator()
    {
         RuleFor(model => model.Name).NotEmpty();
         RuleFor(model => model.Child1).SetValidator(new ChildValidator());
         RuleFor(model => model.Child2).SetValidator(new ChildValidator());
    }
}

如果您不想自动连接子验证器,您可以向子验证器添加空接口:

公共类PersonalDataValidator:AbstractValidator,IChildValidator

然后在你的工厂:

public class FluentValidatorFactory : ValidatorFactoryBase
{
    private readonly IKernel _kernel;
    public FluentValidatorFactory(IKernel kernel)
    {
        _kernel = kernel;
    }
    public override IValidator CreateInstance(Type validatorType)
    {
        IValidator validator = _kernel.Resolve(validatorType) as IValidator;
        ////we dont want that windosr auto wires up all child validators. 
        var childValidator = validator as IChildValidator;
        if (childValidator == null)
        {
            return validator;
        }
            return null;
    }
}