自定义validation属性:比较同一模型中的两个属性
有没有办法在ASP.NET Core中创建自定义属性,以使用ValidationAttribute
validation一个日期属性是否小于模型中的其他日期属性。
让我说我有这个:
public class MyViewModel { [Required] [CompareDates] public DateTime StartDate { get; set; } [Required] public DateTime EndDate { get; set; } = DateTime.Parse("3000-01-01"); }
我想尝试使用这样的东西:
public class CompareDates : ValidationAttribute { public CompareDates() : base("") { } public override bool IsValid(object value) { return base.IsValid(value); } }
我发现其他SOpost建议使用另一个库,但如果可行,我更喜欢坚持使用ValidationAttribute。
您可以为比较两个属性创建自定义validation属性。 这是服务器端validation:
public class MyViewModel { [DateLessThan("End", ErrorMessage = "Not valid")] public DateTime Begin { get; set; } public DateTime End { get; set; } } public class DateLessThanAttribute : ValidationAttribute { private readonly string _comparisonProperty; public DateLessThanAttribute(string comparisonProperty) { _comparisonProperty = comparisonProperty; } protected override ValidationResult IsValid(object value, ValidationContext validationContext) { ErrorMessage = ErrorMessageString; var currentValue = (DateTime)value; var property = validationContext.ObjectType.GetProperty(_comparisonProperty); if (property == null) throw new ArgumentException("Property with this name not found"); var comparisonValue = (DateTime)property.GetValue(validationContext.ObjectInstance); if (currentValue > comparisonValue) return new ValidationResult(ErrorMessage); return ValidationResult.Success; } }
更新 :如果您需要对此属性进行客户端validation,则需要实现IClientModelValidator
接口:
public class DateLessThanAttribute : ValidationAttribute, IClientModelValidator { ... public void AddValidation(ClientModelValidationContext context) { var error = FormatErrorMessage(context.ModelMetadata.GetDisplayName()); context.Attributes.Add("data-val", "true"); context.Attributes.Add("data-val-error", error); } }
AddValidation
方法将从context.Attributes
向您的输入添加属性。
您可以在这里阅读更多IClientModelValidator
作为一种可能的选择自我validation :
您只需要使用方法Validate
实现接口IValidatableObject
,您可以在其中放置validation代码。
public class MyViewModel : IValidatableObject { [Required] public DateTime StartDate { get; set; } [Required] public DateTime EndDate { get; set; } = DateTime.Parse("3000-01-01"); public IEnumerable Validate(ValidationContext validationContext) { int result = DateTime.Compare(StartDate , EndDate); if (result < 0) { yield return new ValidationResult("start date must be less than the end date!", new [] { "ConfirmEmail" }); } } }
您可以在IsValid方法中比较两个日期。
public class CompareDates : ValidationAttribute { protected override ValidationResult IsValid(object value, ValidationContext validationContext) { //get your startdate & end date from model and value //perform comparison if (StartDate < EndDate) { return new ValidationResult ("start date must be less than the end date"); } else { return ValidationResult.Success; } } }
基于Alexander Gore的响应,我建议进行更好的通用validation(并且它与.Net核心兼容)。 如果要使用GreatherThan或LessThan逻辑(无论类型是什么)比较属性,您可以validation它们是否已实现IComparable
接口。 如果两个属性都有效,则可以使用CompareTo
实现。 此规则也适用于DateTime
和数字类型
少于
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter)] public class LessThanAttribute : ValidationAttribute { private readonly string _comparisonProperty; public LessThanAttribute(string comparisonProperty) { _comparisonProperty = comparisonProperty; } protected override ValidationResult IsValid(object value, ValidationContext validationContext) { ErrorMessage = ErrorMessageString; if (value.GetType() == typeof(IComparable)) { throw new ArgumentException("value has not implemented IComparable interface"); } var currentValue = (IComparable)value; var property = validationContext.ObjectType.GetProperty(_comparisonProperty); if (property == null) { throw new ArgumentException("Comparison property with this name not found"); } var comparisonValue = property.GetValue(validationContext.ObjectInstance); if (comparisonValue.GetType() == typeof(IComparable)) { throw new ArgumentException("Comparison property has not implemented IComparable interface"); } if (!ReferenceEquals(value.GetType(), comparisonValue.GetType())) { throw new ArgumentException("The properties types must be the same"); } if (currentValue.CompareTo((IComparable)comparisonValue) >= 0) { return new ValidationResult(ErrorMessage); } return ValidationResult.Success; } }
比…更棒
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter)] public class GreaterThanAttribute : ValidationAttribute { private readonly string _comparisonProperty; public GreaterThanAttribute(string comparisonProperty) { _comparisonProperty = comparisonProperty; } protected override ValidationResult IsValid(object value, ValidationContext validationContext) { ErrorMessage = ErrorMessageString; if (value.GetType() == typeof(IComparable)) { throw new ArgumentException("value has not implemented IComparable interface"); } var currentValue = (IComparable)value; var property = validationContext.ObjectType.GetProperty(_comparisonProperty); if (property == null) { throw new ArgumentException("Comparison property with this name not found"); } var comparisonValue = property.GetValue(validationContext.ObjectInstance); if (comparisonValue.GetType() == typeof(IComparable)) { throw new ArgumentException("Comparison property has not implemented IComparable interface"); } if (!ReferenceEquals(value.GetType(), comparisonValue.GetType())) { throw new ArgumentException("The properties types must be the same"); } if (currentValue.CompareTo((IComparable)comparisonValue) < 0) { return new ValidationResult(ErrorMessage); } return ValidationResult.Success; } }
在预订环境中,示例可以如下:
public DateTime CheckInDate { get; set; } [GreaterThan("CheckInDate", ErrorMessage = "CheckOutDate must be greater than CheckInDate")] public DateTime CheckOutDate { get; set; }