子属性的选择性验证 - MVC中的流畅验证

时间:2012-01-24 17:29:58

标签: c# asp.net-mvc ninject fluentvalidation

我正在使用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上的所有子属性。

有没有什么方法可以防止这种情况发生而不会摆脱Ninject模块?

3 个答案:

答案 0 :(得分:2)

由于自动连接无法有条件地理解何时在模型绑定期间应用ChildValidator类,因此您似乎有几个选择:

  1. 决定重用子视图模型是否重要。面对这种情况,如果Child对象不是很复杂,那么我可能会将子节点折叠到该视图的父节点中不过是一些分别使用Child对象的视图。我总是更不愿意使用视图模型进行超级DRY,因为根据我的经验,页面结构会随着时间的推移而发生分歧。
  2. Clear ModelState errors for Child2.从这里开始,您可以完全控制Child2的验证,包括在此唯一上下文中单独使用Child2的验证器并手动应用它。这是我喜欢FluentValidation的原因之一 - 能够在不同的上下文中将不同的验证逻辑应用于相同的视图模型,与数据注释不同。
  3. 自动连线的价值(即它排除的所有额外代码)将排除在这种情况下将其关闭的选项,IMO。

答案 1 :(得分:0)

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

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

答案 2 :(得分:0)

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

公共类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;
    }
}