Validation Block – Conditional Validation Redux

You can see my initial thoughts on conditional validation here.  I have a follow-up problem that required a different approach (and a Kludge).  The regular expression solution attribution validation solution only works for the single property.  What about validation for Two (or many) properties?  For example, assume you have a Person Class like so:

    public class Person

    {

        public int PersonId { get; set; }

        public string PersonName { get; set; }

        public DateTime DateOfBirth { get; set; }

        public DateTime DateOfDeath { get; set; }

 

 

        public override string ToString()

        {

            return PersonName;

        }

    }

Adding some simple attribute validation gives us this:

    public class Person

    {

        public int PersonId { get; set; }

        [StringLengthValidator(10, MessageTemplate = "Name is 10 characters")]

        public string PersonName { get; set; }

        [DateTimeRangeValidator(DateTime.Today, MessageTemplate = "Can’t be born in the future")]

        public DateTime DateOfBirth { get; set; }

        public DateTime DateOfDeath { get; set; }

 

 

        public override string ToString()

        {

            return PersonName;

        }

    }

But I have one more validation I need to implement – a person can not have a DateOfDeath before their DateOfBirth.

My First thought was to in-line a DateTimeRangeValidator like so

        [DateTimeRangeValidator(this.DateOfBirth, MessageTemplate = "You Can’t Die Before You are Born")]

        public DateTime DateOfDeath { get; set; }

However, you get this error – Keyword this is not available in the Current Context

 Note that you CAN do it for static fields, but that won’t help with 95% of the DTOs out there because DTOs are usually implemented as instance members – especially in a web solution.

 

My next thought was to use Self-Validation like so:

    [HasSelfValidation]

    public class Person

    {

        public int PersonId { get; set; }

        [StringLengthValidator(10, MessageTemplate = "Name is 10 characters")]

        public string PersonName { get; set; }

        [DateTimeRangeValidator(DateTime.Today, MessageTemplate = "Can’t be born in the future")]

        public DateTime DateOfBirth { get; set; }

        public DateTime DateOfDeath { get; set; }

 

        [SelfValidation]

        public void CheckDates(ValidationResults results)

        {

            if (DateOfBirth > DateOfDeath)

            {

                ValidationResult validationResult = new ValidationResult("DOB > DOD",

                    this, string.Empty, string.Empty, null);

                results.AddResult(validationResult);

            }

        }

 

        public override string ToString()

        {

            return PersonName;

        }

    }

This works fine in unit testing.  The problem is that the PropertyProxyValidation in ASP.NET solutions do not work with conditional validation – they only work with Attribute-based validation.  I seemed to be stuck (and I still am, really) so I came up with a Kludge.

I added a validator to the DateOfDeath Property like so:

        [DateTimeRangeValidator("1900-01-01T00:00:00", MessageTemplate = "You Can’t Die Before You are Born", Ruleset

        = "Zombie")]

        public DateTime DateOfDeath { get; set; }

 

Note the addition of the ruleset.

I then added a PropertyProxyValidator to the DateOfDeath field with the enabled Property set to false:

 

I then created a method in the code-behind of the web-page creates a new instance of the Person class using the fields from the web form and runs validation.   You need to run this validation before any data binding to keep in align with the Page lifecycle.

 

        private void BirthDeathDateValidation()

        {

            TextBox textBoxPersonId = this.DetailsView1.FindControl("TextBox4") as TextBox;

            TextBox textBoxPersonName = this.DetailsView1.FindControl("TextBox2") as TextBox;

            TextBox textBoxPersonDOB = this.DetailsView1.FindControl("TextBox1") as TextBox;

            TextBox textBoxPersonDOD = this.DetailsView1.FindControl("TextBox3") as TextBox;

 

 

                Person person = new Person();

                person.PersonId = Int32.Parse(textBoxPersonId.Text);

                person.PersonName = textBoxPersonName.Text;

                person.DateOfBirth = DateTime.Parse(textBoxPersonDOB.Text);

                person.DateOfDeath = DateTime.Parse(textBoxPersonDOD.Text);

 

                Microsoft.Practices.EnterpriseLibrary.Validation.ValidationResults results =

                    new Microsoft.Practices.EnterpriseLibrary.Validation.ValidationResults();

                person.CheckDates(results);

 

                if (results.Count > 0)

                {

                    PropertyProxyValidator propertyProxyValidator =

                        this.DetailsView1.FindControl("PropertyProxyValidator3") as PropertyProxyValidator;

                    propertyProxyValidator.RulesetName = "Zombie";

                    propertyProxyValidator.Enabled = true;

                }

            }

 

        }

 

Now, if the DateOfDeath happensbefore DateOfBirth, the ruleset is switched to the appropriate ruleset and the validator is enabled.

 

Like I said, a Kludge, but I don’t see a better option.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: