Tuesday, September 01, 2009 10:49 AM srkirkland

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.

Filed under: , , ,

Comments

# Enterprise Library Validation – Custom Validators - Scott's Blog

Wednesday, September 02, 2009 1:35 AM by 9eFish

9efish.感谢你的文章 - Trackback from 9eFish

# re: Enterprise Library Validation – Custom Validators

Wednesday, September 02, 2009 11:47 AM by Chris Lively

This was perfect.

Thank you.

# re: Enterprise Library Validation – Custom Validators

Friday, February 26, 2010 3:53 AM by muffle

This is still server-side validation????

# re: Enterprise Library Validation – Custom Validators

Friday, February 26, 2010 4:34 PM by srkirkland

@muffle,

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

# re: Enterprise Library Validation – Custom Validators

Friday, March 05, 2010 3:19 AM by fred

I know it is server-side. But I would like to use client side. Can we get the Enterprise Library to work Client-Side???? If so do you know how it can be done? I've been struggling with this issue for days. I have a large MVC project pending and I want to EL as DAL and Validation. The DAL tested fine today. I just need client-side validation and I will be happy.

Any ideas?  :-)

# re: Enterprise Library Validation – Custom Validators

Thursday, March 11, 2010 7:55 PM by srkirkland

@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.

# re: Enterprise Library Validation – Custom Validators

Saturday, March 26, 2011 3:43 AM by generic

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.

# re: Enterprise Library Validation – Custom Validators

Wednesday, May 04, 2011 5:56 AM by Sumanth

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”

Leave a Comment

(required) 
(required) 
(optional)
(required)