Conditional validation?

Topics: Validation Application Block
May 31, 2007 at 10:41 PM
Edited May 31, 2007 at 10:41 PM
Suppose i have 2 classes:

Article
{
bool discontinued
List<Part> parts
}

Part
{
bool discontinued
}


I would like to validate that all parts are discontinued=true if my article is discontinued=true. Is this possible without the use of a custom validator? I'm using a configuration file as configuration source.

I know that i can create a Object Collection Validator on the Article.parts property, that then calls a specific ruleset on my Part type, which ensures that discontinued is true. However, how do i stop that from happening if discontinued is false on my Article?
Jun 1, 2007 at 5:08 PM
My initial thought is SelfValidation on the Part Class.

Assuming Part has a reference to its parent, here is a bit of psuedocode on what I am thinking-

[HasSelfValidation]
public class Part
{
    Article article;
    bool discontinued;
 
    [SelfValidation]
    public void Validate(ValidationResults results)
    {
        if (article.Discontinued)
        {
            if (!this.Discontinued)
                // error: Add ValidationResults to results class...
        }
    }
}

Regards,

Dave

____________________________

David Hayden
Microsoft MVP C#
Jun 11, 2007 at 8:43 PM
Edited Jun 12, 2007 at 1:02 PM
Yes, that seems like a clear-cut candidate for SelfValidation. I've run into other similar scenarios where I've been able to use a combination of RuleSets and SelfValidation as a solution. Consider the following:

[HasSelfValidation()]
public class Contact
{
   string name;
   string email;
   [RegularExpressionValidator("<US Phone Regex>", RuleSet="UsaValidation")]
   [RegularExpressionValidator("<CA Phone Regex>", RuleSet="CanadaValidation")]
   string phone;
   string country;
 
   [SelfValidation()]
   public void DoValidate(ValidationResults results)
   {
      switch (this.country)
      {
         case "US":
            Validator usaValidator = ValidationFactory.CreateValidator(this.GetType(), Rulesets.UsaValidation);
            usaValidator.Validate(this, results);
            break;
         case "CA":
            Validator caValidator = ValidationFactory.CreateValidator(this.GetType(), Rulesets.CanadaValidation);
            usaValidator.Validate(this, results);
            break;
      }
   }
}
I'd love to see some mechanism for making the validators conditional - perhaps an attribute or a set of additional named parameters. I'll illustrate how I'd envision the named parameters solution working:

public class Contact
{
   string name;
   string email;
   [RegularExpressionValidator("<US Phone Regex>", ConditionProperty="country", ConditionValue="US", ConditionOperator=ComparisonOperator.Equal)]
   [RegularExpressionValidator("<Canada Phone Regex>", ConditionProperty="country", ConditionValue="CA", ConditionOperator=ComparisonOperator.Equal)]
   string phone;
   string country;
}
If specified, the Validator would use these parameters as a way of determining if the rule applies. It would use reflection to compare the value of the specified property to whatever value is specified. The implementation would probably be very similar to the PropertyComparisonValidator...in fact, it could use the ComparisonOperator enum to indicate the type of comparison to perform. Only if this condition evaluates to true would the validator be executed. I'm not sure if all those extra named parameters is very desirable, but I'm sure there's another more elegant solution. If I get ambitious enough to modify the EntLib source myself, I'll post some stuff over in EntLibContrib.
Jun 12, 2007 at 7:55 AM
ericm,

The most intiuitive way (imho), would probbably be to make the condition dependant on the outcome of a validation, using an existing validator to check for whatever value you need.