Advanced Form Validation Logic: Cross-Field Dependencies
In this lesson, you will learn how to create custom validation attributes to enforce rules that depend on the relationship between two or more properties in your form models.
The Challenge of Contextual Validation
Standard data annotations like [Required] or [Range] operate in isolation. However, real-world business logic often requires "cross-field dependency." For example, imagine a "Return Date" that must be at least one day after the "Departure Date." Because standard attributes don't inherently know about other properties in the class, we must implement custom logic by overriding the IsValid method of the ValidationAttribute base class.
Implementing a Cross-Field Validator
To validate dependent fields, we use the ValidationContext object passed into IsValid. This context provides access to the entire object being validated via the ObjectInstance property.
Consider this DateRangeAttribute:
public class DateRangeAttribute : ValidationAttribute
{
private readonly string _comparisonProperty;
public DateRangeAttribute(string comparisonProperty)
{
_comparisonProperty = comparisonProperty;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var currentValue = (DateTime)value;
var property = validationContext.ObjectType.GetProperty(_comparisonProperty);
var comparisonValue = (DateTime)property.GetValue(validationContext.ObjectInstance);
if (currentValue <= comparisonValue)
{
return new ValidationResult(ErrorMessage ?? "Date must be after the start date.");
}
return ValidationResult.Success;
}
}
Applying the Logic
You apply this attribute to your model, passing the name of the property you are comparing against:
public class BookingRequest
{
public DateTime DepartureDate { get; set; }
[DateRange(nameof(DepartureDate), ErrorMessage = "Return date must be after departure.")]
public DateTime ReturnDate { get; set; }
}
When the EditForm in Blazor triggers validation, the framework invokes IsValid. By using reflection to inspect the ObjectInstance, your attribute can now perform complex calculations based on the state of the entire form, ensuring your data integrity remains ironclad regardless of field complexity.
Key Takeaway: By accessing the ValidationContext.ObjectInstance, you can break free from isolated property validation and implement sophisticated business rules that ensure your form data is consistent across multiple inputs.