Asp.net mvc 3 用于EditorTemplate的嵌套模型的ASP.NET MVC3条件验证
假设您有一个viewModel:Asp.net mvc 3 用于EditorTemplate的嵌套模型的ASP.NET MVC3条件验证,asp.net-mvc-3,validation,model,Asp.net Mvc 3,Validation,Model,假设您有一个viewModel: public class CreatePersonViewModel { [Required] public bool HasDeliveryAddress {get;set;} // Should only be validated when HasDeliveryAddress is true [RequiredIf("HasDeliveryAddress", true)] public Address Addres
public class CreatePersonViewModel
{
[Required]
public bool HasDeliveryAddress {get;set;}
// Should only be validated when HasDeliveryAddress is true
[RequiredIf("HasDeliveryAddress", true)]
public Address Address { get; set; }
}
型号地址如下所示:
public class Address : IValidatableObject
{
[Required]
public string City { get; set; }
[Required]
public string HouseNr { get; set; }
[Required]
public string CountryCode { get; set; }
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
[Required]
public string ZipCode { get; set; }
[Required]
public string Street { get; set; }
#region IValidatableObject Members
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
string[] requiredFields;
var results = new List<ValidationResult>();
// some custom validations here (I removed them to keep it simple)
return results;
}
#endregion
}
公共类地址:IValidatableObject
{
[必需]
公共字符串City{get;set;}
[必需]
公共字符串HouseNr{get;set;}
[必需]
公共字符串CountryCode{get;set;}
[必需]
公共字符串名{get;set;}
[必需]
公共字符串LastName{get;set;}
[必需]
公共字符串ZipCode{get;set;}
[必需]
公共字符串Street{get;set;}
#表对象成员所在的区域
公共IEnumerable验证(ValidationContext ValidationContext)
{
字符串[]必填字段;
var results=新列表();
//这里有一些自定义验证(我删除了它们以保持简单)
返回结果;
}
#端区
}
有些人建议为Address创建一个viewmodel,并在其中添加一些自定义逻辑,但我需要一个Address
的实例来传递给我的editor模板以获取Address
这里的主要问题是地址的验证是在我的PersonViewModel验证之前完成的,所以我无法阻止它
注意:RequiredIfAttribute是一个自定义属性,它正好满足我对简单类型的需求 西蒙·因斯(Simon Ince)的alpha版本似乎可以做你想做的事
更新
据我所知,“问题”在于类,它验证模型的基础是,如果它找到一个验证属性,它会询问该值是否有效(实际上相当合理!),它没有层次结构的概念。为了支持您所需的功能,您必须编写一个自定义模型绑定器,该绑定器根据您的声明性标记进行绑定,然后根据需要进行验证。
如果您确实编写了这样一个类,它可能是MVC futures的一个很好的候选者。如果您使用了DataAnnotation或IValidatableObject,而不是在非常复杂的场景中限制验证能力的DataAnnotation或IValidatableObject,这将是一件轻而易举的事:
public class CreatePersonViewModelValidator : AbstractValidator<CreatePersonViewModel>
{
public CreatePersonViewModelValidator()
{
RuleFor(x => x.Address)
.SetValidator(new AddressValidator())
.When(x => x.HasDeliveryAddress);
}
}
公共类CreatePersonViewModelValidator:AbstractValidator
{
公共CreatePersonViewModelValidator()
{
规则(x=>x.Address)
.SetValidator(新的AddressValidator())
.When(x=>x.HasDeliveryAddress);
}
}
遗憾的是,他的RequiredIfAttribute只适用于简单类型,而不适用于复杂类型,如“我的地址”。我已经在使用他的RequiredIfAttribute了。@Peter更新了建议的解决方案,不幸的是,据我所知,这样的解决方案已经不存在了,所以你将有新的突破!我想说您的观察是正确的,不幸的是,我没有时间创建具有这种功能的自定义ModelBinder,更不用说彻底测试了。目前,FluentValidation似乎是一个更好的选择。我真的很想看到这样的东西在MVC的未来版本中实现。因为现在我觉得MVC在现实世界的应用程序中是缺乏的。我从来没有听说过这个库,但到目前为止我印象非常深刻。谢谢@Peter,我从ASP.NET MVC 1的第一个版本开始使用这个库。当我看到微软提供数据注释来执行验证时,我对自己说:WTF!!!与命令式验证相比,声明式验证的局限性要大得多。有些场景很难使用这些属性以声明方式表达。我的意思是,他们的工作非常好的东西,如要求,最小值,最大值。。。这正是互联网上充斥的东西,但一旦你开始编写真实世界的应用程序,你就会意识到它们的局限性。因此,只需安装包FluentValidation.MVC3
,在你的应用程序启动时添加以下行:FluentValidationModelValidatorProvider.Configure()代码>,摆脱所有的数据注释垃圾,开始为视图模型编写真正的验证器。这样做的另一个好处是验证逻辑与视图模型是分开的,并且可以是隔离的。您还可以根据HTTP参数对规则进行分组并有条件地应用它们,……我看到它与常规DataAnnotation完美集成。所以,现在,为了让同事们的学习曲线保持在一个较低的水平,我将只在复杂的验证中使用FluentValidation,并保留DataAnnotation所需的愚蠢的验证。