使用数据注释自定义模型依赖属性的验证
由于现在我已经使用了优秀的FluentValidation库来验证我的模型类。 在web应用程序中,我将它与jquery.validate插件一起使用来执行客户端验证。 一个缺点是许多验证逻辑在客户端重复,不再集中在一个地方。
出于这个原因,我正在寻找替代品。 有很多示例显示了使用数据注释来执行模型验证。 它看起来很有希望。 我找不到的一件事是如何验证依赖于另一个属性值的属性。
我们以下面的模型为例:
public class Event
{
[Required]
public DateTime? StartDate { get; set; }
[Required]
public DateTime? EndDate { get; set; }
}
我想确保EndDate
大于StartDate
。 我可以编写一个扩展ValidationAttribute的自定义验证属性,以执行自定义验证逻辑。 不幸的是,我找不到获得模型实例的方法:
public class CustomValidationAttribute : ValidationAttribute
{
public override bool IsValid(object value)
{
// value represents the property value on which this attribute is applied
// but how to obtain the object instance to which this property belongs?
return true;
}
}
我发现CustomValidationAttribute似乎做的工作,因为它有这个ValidationContext
属性包含被验证的对象实例。 不幸的是,该属性仅在.NET 4.0中添加。 所以我的问题是:我可以在.NET 3.5 SP1中实现相同的功能吗?
更新:
似乎FluentValidation已经支持ASP.NET MVC 2中的客户端验证和元数据。
尽管如此,如果数据注释可以用来验证从属属性,仍然会很高兴。
MVC2附带了一个示例“PropertiesMustMatchAttribute”,它显示了如何让DataAnnotations为您工作,并且它应该可以在.NET 3.5和.NET 4.0中使用。 该示例代码如下所示:
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
public sealed class PropertiesMustMatchAttribute : ValidationAttribute
{
private const string _defaultErrorMessage = "'{0}' and '{1}' do not match.";
private readonly object _typeId = new object();
public PropertiesMustMatchAttribute(string originalProperty, string confirmProperty)
: base(_defaultErrorMessage)
{
OriginalProperty = originalProperty;
ConfirmProperty = confirmProperty;
}
public string ConfirmProperty
{
get;
private set;
}
public string OriginalProperty
{
get;
private set;
}
public override object TypeId
{
get
{
return _typeId;
}
}
public override string FormatErrorMessage(string name)
{
return String.Format(CultureInfo.CurrentUICulture, ErrorMessageString,
OriginalProperty, ConfirmProperty);
}
public override bool IsValid(object value)
{
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(value);
object originalValue = properties.Find(OriginalProperty, true /* ignoreCase */).GetValue(value);
object confirmValue = properties.Find(ConfirmProperty, true /* ignoreCase */).GetValue(value);
return Object.Equals(originalValue, confirmValue);
}
}
当你使用这个属性,而不是把它放在模型类的一个属性上时,你把它放在类本身上:
[PropertiesMustMatch("NewPassword", "ConfirmPassword", ErrorMessage = "The new password and confirmation password do not match.")]
public class ChangePasswordModel
{
public string NewPassword { get; set; }
public string ConfirmPassword { get; set; }
}
当您的自定义属性上调用“IsValid”时,整个模型实例将被传递给它,以便您可以通过这种方式获取相关属性值。 您可以轻松地遵循此模式来创建日期比较属性,甚至可以创建更一般的比较属性。
Brad Wilson在他的博客上展示了如何添加验证的客户端部分,尽管我不确定这个示例是否可以在.NET 3.5和.NET 4.0中工作。
我有这个问题,最近开源了我的解决方案:http://foolproof.codeplex.com/
以上例子的万无一失的解决方案是:
public class Event
{
[Required]
public DateTime? StartDate { get; set; }
[Required]
[GreaterThan("StartDate")]
public DateTime? EndDate { get; set; }
}
而不是PropertiesMustMatch可以在MVC3中使用的CompareAttribute。 根据这个链接http://devtrends.co.uk/blog/the-complete-guide-to-validation-in-asp.net-mvc-3-part-1:
public class RegisterModel
{
// skipped
[Required]
[ValidatePasswordLength]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[Compare("Password", ErrorMessage = "The password and confirmation do not match.")]
public string ConfirmPassword { get; set; }
}
CompareAttribute是一个新的非常有用的验证器,它实际上并不是System.ComponentModel.DataAnnotations的一部分,但已被团队添加到System.Web.Mvc DLL中。 虽然命名不是特别好(唯一的比较是检查是否相等,所以EqualTo可能更明显),但从使用情况中很容易看出,此验证程序检查一个属性的值是否等于另一个属性的值。 您可以从代码中看到,该属性接受一个字符串属性,该字符串属性是您正在比较的其他属性的名称。 这种验证器的经典用法就是我们在这里使用它的地方:密码确认。
链接地址: http://www.djcxy.com/p/56583.html上一篇: Custom model validation of dependent properties using Data Annotations
下一篇: Can I restrict a custom attribute to void methods only?