子属性的选择性validation – MVC中的流畅validation

我正在使用Fluent Validation与Ninject.Web.Mvc.FluentValidation库自动连接所有validation器(并使用dependency injection来创建validation器)。

我创建了以下模型:

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

使用以下validation器:

 public class ParentValidator : AbstractValidator { public ParentValidator() { RuleFor(model => model.Name).NotEmpty(); RuleFor(model => model.Child1).SetValidator(new ChildValidator()); } } public class ChildValidator : AbstractValidator { 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)  } @model Child @Html.EditorFor(model => model.ChildProperty) @Html.EditorFor(model => model.ChildProperty) 

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

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

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

  1. 确定重用子视图模型是否重要。 面对这种情况,如果Child对象不是很复杂并且没有多个视图分别使用Child对象,我可能会将子节点折叠为此视图的父节点。 我总是更不愿意使用视图模型进行超级DRY,因为根据我的经验,页面结构会随着时间的推移而发生分歧。
  2. 清除Child2的ModelState错误。 从这里开始,您可以完全控制Child2的validation,包括在此唯一上下文中单独使用Child2的validation器并手动应用它。 这是我喜欢FluentValidation的原因之一 – 能够在不同的上下文中将不同的validation逻辑应用于相同的视图模型,这与数据注释不同。

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

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

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

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

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