Enterprise Library Validation – Custom Validators

In this post I am going to create a custom email validator that will integrate with the Enterprise Library Validation Application Block.

My goal here is to be able to use an [EmailValidator] attribute on any property of any class and have it do the expected email format validation through Enterprise Library.  My other requirement is that an empty or null string will not fail validation (because of course I want to be able to have an optional email property).

Endgame:

   1: public class EmailValTestClass
   2: {
   3:     [EmailValidator]
   4:     public string Email { get; set; }
   5: }

In order to create an Enterprise Library Validation extension, you need to create two classes: A validator class that does the heavy lifting, and an attribute that will allow you to decorate your properties as I did above.

 

Creating the Validator

The first class should inherit Validator<T> where T is the type of property to validate (I am going to use a string for email, but you could use any type or even IEnumerable for list types). This will require you to override the DefaultMessageTemplate string property and the void DoValidate() method. The DoValidate() is where the actual work is done:

   1: namespace CAESArch.Core.Validators
   2: {
   3:     public class EmailValidator : Validator<string>
   4:     {
   5:         static readonly Regex EmailRegex = new Regex(@"\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*");
   6:  
   7:         public EmailValidator(string tag) : base(string.Empty, tag) { }
   8:  
   9:         protected override string DefaultMessageTemplate
  10:         {
  11:             get { throw new NotImplementedException(); }
  12:         }
  13:  
  14:         /// <summary>
  15:         /// Validate that this string is a valid email address
  16:         /// RegEx: \w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*
  17:         /// </summary>
  18:         protected override void DoValidate(string objectToValidate, object currentTarget, string key, ValidationResults validationResults)
  19:         {
  20:             if (string.IsNullOrEmpty(objectToValidate))
  21:             {
  22:                 return;  //We are not going to validate for the null possibility (use a required validator for that)
  23:             }
  24:  
  25:             Match match = EmailRegex.Match(objectToValidate);
  26:  
  27:             if (!match.Success) //If the match does not succeed, then it is an invalid email address
  28:             {
  29:                 LogValidationResult(validationResults, "Email Address Format Is Not Valid", currentTarget, key);
  30:             }
  31:         }
  32:     }
  33: }

Creating the Attribute

The second class allows you to use your new validator as an attribute, and is pretty straight forward. Just inherit from ValidatorAttribute and override the DoCreateValidator method:

   1: namespace CAESArch.Core.Validators
   2: {
   3:     [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
   4:     public class EmailValidatorAttribute : ValidatorAttribute
   5:     {
   6:         protected override Validator DoCreateValidator(Type targetType)
   7:         {
   8:             return new EmailValidator(Tag);
   9:         }
  10:     }
  11: }

That’s all you have to do!  Now let’s run a few tests (which of course were created in advance, like any good TDD programmer would do…):

Testing your Validator

First let’s test our requirement that null or empty strings do not cause validation failure:

   1: [TestMethod]
   2: public void ClassValidIfEmailIsEmpty()
   3: {
   4:     var testClass = new EmailValTestClass { Email = string.Empty };
   5:  
   6:     var isTestClassValid = Validation.Validate(testClass).IsValid;
   7:  
   8:     Assert.AreEqual(true, isTestClassValid, "blank email should pass validaton");
   9: }
  10:  
  11: [TestMethod]
  12: public void ClassValidIfEmailIsNull()
  13: {
  14:     var testClass = new EmailValTestClass {Email = null};
  15:  
  16:     var isTestClassValid = Validation.Validate(testClass).IsValid;
  17:     
  18:     Assert.AreEqual(true, isTestClassValid, "Null email should pass validaton");
  19: }

Now we’ll run the tests for a few bad email addresses and one good email address and make sure the validation results are what we expect:

   1: [TestMethod]
   2: public void ClassInvalidIfEmailIsMissingDomain()
   3: {
   4:     var testClass = new EmailValTestClass { Email = "invalidemail@google" };
   5:  
   6:     var isTestClassValid = Validation.Validate(testClass).IsValid;
   7:  
   8:     Assert.AreEqual(false, isTestClassValid);
   9: }
  10:  
  11: [TestMethod]
  12: public void ClassInvalidIfEmailIsMissingAtSign()
  13: {
  14:     var testClass = new EmailValTestClass { Email = "invalidemail.com" };
  15:  
  16:     var isTestClassValid = Validation.Validate(testClass).IsValid;
  17:  
  18:     Assert.AreEqual(false, isTestClassValid);
  19: }
  20:  
  21: [TestMethod]
  22: public void ClassValidIfEmailIsValid()
  23: {
  24:     var testClass = new EmailValTestClass { Email = "validemail@someplace.com" };
  25:  
  26:     var isTestClassValid = Validation.Validate(testClass).IsValid;
  27:  
  28:     Assert.AreEqual(true, isTestClassValid, "Email should pass validaton");
  29: }

And since the tests all come up green, I can sleep peacefully tonight knowing that email addresses will be formatted properly before being stored.

7 Comments

  • This was perfect.
    Thank you.

  • This is still server-side validation????

  • @muffle,
    Yes, Enterprise Library Validation is a server side validation framework.

  • @fred,
    Sorry, Enterprise Library works server-side only. EntLib's validation doesn't allow us to query validation rules on individual properties so you can't emit client-side rules. Take a look at DataAnnotations or NHibernate Validator if you want to do server & client validation.

  • Surprisingly! It is like you understand my mind! You seem to know so much about this, just like you wrote the book in it or something. I think that you can do with some pics to drive the content home a bit, but other than that, this is informative blog post. A good read. I’ll definitely revisit again.

  • Thanks for your valuable post Scott.
    How can I display user defined error message?
    Even if I use
    [EmailValidator(ErrorMessage="Demo Email")]
    public string Email {get;set;}

    I got the same message “Email Address Format Is Not Valid”

  • Hi Sumanth,

    You have to change two line in the EmailValidator class.

    Change line 11 to:

    get { return "Email Address Format Is Not Valid"; }

    Change line 29 to:

    LogValidationResult(validationResults, GetMessage(objectToValidate, key), currentTarget, key);

    Then your custom will appear and a default message is available when nothing is specified.

    Your property should be annotated like:

    [EmailValidator(MessageTemplate = "Demo Email")]
    public string Email { get; set; }

    Hope this helps you and others,

    Best regards,

    Guus

Comments have been disabled for this content.