Custom Validation Attributes: Comparing two properties in the same model
Is there a way to create a custom attribute in ASP.NET Core to validate if one date property is less than other date property in a model using ValidationAttribute
.
Lets say I have this:
public class MyViewModel
{
[Required]
[CompareDates]
public DateTime StartDate { get; set; }
[Required]
public DateTime EndDate { get; set; } = DateTime.Parse("3000-01-01");
}
I am trying to use something like this:
public class CompareDates : ValidationAttribute
{
public CompareDates()
: base("") { }
public override bool IsValid(object value)
{
return base.IsValid(value);
}
}
I found other SO post that proposes to use another library, But I prefer to stick with ValidationAttribute if that was doable.
You can create a custom validation attribute for comparison two properties. It's a server side 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;
}
}
Update:
If you need a client side validation for this attribute, you need implement an IClientModelValidator
interface:
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);
}
}
The AddValidation
method will add attributes to your inputs from context.Attributes
.
You can read more here IClientModelValidator
As one possible option self-validation:
You just need to Implement an interface IValidatableObject
with the method Validate()
, where you can put your validation code.
public class MyViewModel : IValidatableObject
{
[Required]
public DateTime StartDate { get; set; }
[Required]
public DateTime EndDate { get; set; } = DateTime.Parse("3000-01-01");
public IEnumerable<ValidationResult> 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" });
}
}
}