Entity Framework: Creating Custom Validation Attributes, Part 1

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.

Written by Jonathan "JD" Danylko • Last Updated: • MVC •
Guards standing guard

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.

ASP.NET 8 Best Practices on Amazon

ASP.NET 8 Best Practices by Jonathan Danylko


Reviewed as a "comprehensive guide" and a "roadmap to excellence" with over 120 Best Practices for ASP.NET Core 8, Jonathan's first book by Packt Publishing explores proven techniques for every phase of the SDLC.

Learn industry-standard concepts to improve your coding, debugging, and deployment of ASP.NET Core websites.

Order now on Amazon.com button

Picture of Jonathan "JD" Danylko

Jonathan "JD" Danylko is an author, web architect, and entrepreneur who's been programming for over 30 years. He's developed websites for small, medium, and Fortune 500 companies since 1996.

He currently works at Insight Enterprises as an Architect.

When asked what he likes to do in his spare time, he replies, "I like to write and I like to code. I also like to write about code."

comments powered by Disqus