Entity Framework: Creating Custom Validation Attributes, Part 1

February 22nd, 2016

Validation attributes are used for validating entities when a user enters data from a web page. Today's post covers how to create your own custom validation attributes for those pesky hard-to-reach validations.

When you create new entities using Entity Framework, you have the option to add validations to each of your properties. When these entities are presented to the user, the validation attributes are executed to make sure the user doesn't enter in something invalid.

An example of a validation attribute would be the [Required] or [StringLength] attributes.

There are a number of attributes you can use with your entities.

MSDN has the entire list of validation attributes.

Today, we'll cover how to setup your own validation attributes and provide an interesting validation scenario.

I Need A Date[Time]!

I just ran into a need for a custom validation attribute at work. What if we have one date as a StartDate and another as a StopDate where the StopDate HAS to be greater than the StartDate?

Even though we have the CompareAttribute available to us, this is not the kind of comparison we need to achieve for...let's say...two dates.

Since this is easy if..then logic, we can demonstrate the reusability by creating a simple validation attribute to achieve our date comparison.

So taking a cue from the CompareAttribute, I decided to make a DateCompareAttribute class with a DateTimeComparer enum type specific to how we want to compare the two dates.

ValidationAttributes\DateCompareAttribute.cs

public class DateCompareAttribute : ValidationAttribute
{
    private readonly string _propertyName;
    private readonly DateTimeComparer _comparerType;

    public DateCompareAttribute(string propertyName, DateTimeComparer comparerType)     {         _propertyName = propertyName;         _comparerType = comparerType;     }
    protected override ValidationResult IsValid(object firstValue, ValidationContext validationContext)     {         var propertyInfo = validationContext.ObjectType.GetProperty(_propertyName);         if (propertyInfo != null)             return new ValidationResult(String.Format("Property {0} does not exist.", _propertyName));
        var propertyValue = propertyInfo.GetValue(validationContext.ObjectInstance, null);
        switch (_comparerType)         {             case DateTimeComparer.IsEqualTo:                 if ((DateTime)propertyValue == (DateTime)firstValue)                 {                     return ValidationResult.Success;                 }                 break;             case DateTimeComparer.IsGreaterThan:                 if ((DateTime)propertyValue > (DateTime)firstValue)                 {                     return ValidationResult.Success;                 }                 break;             case DateTimeComparer.IsGreaterThanOrEqualTo:                 if ((DateTime)propertyValue >= (DateTime)firstValue)                 {                     return ValidationResult.Success;                 }                 break;             case DateTimeComparer.IsLessThan:                 if ((DateTime)propertyValue < (DateTime)firstValue)                 {                     return ValidationResult.Success;                 }                 break;             case DateTimeComparer.IsLessThanOrEqualTo:                 if ((DateTime)propertyValue <= (DateTime)firstValue)                 {                     return ValidationResult.Success;                 }                 break;         }
        return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));     } }

ValidationAttributes\DateTimeComparer.cs

public enum DateTimeComparer
{
    IsEqualTo,
    IsLessThan,
    IsGreaterThan,
    IsLessThanOrEqualTo,
    IsGreaterThanOrEqualTo
}

To use this validation attribute, we place our attribute on our DateTime requiring validation.

public class Post
{
    public DateTime EffectiveDate { get; set; }

    [DateCompare("EffectiveDate", DateTimeComparer.IsGreaterThan)]     public DateTime ExpirationDate { get; set; }

Conclusion

Now that we've finished our validation, you can create your own validation attributes. I will be adding more later if there's a major request for them.

Until next time.

(It seems there was a major request for the attributes so there's a part 2).

Did you ever create your own validation attributes? What validations did you solve? Post your comments below.