Chaining Rulesets

Topics: Validation Application Block
May 3, 2007 at 9:30 AM
Edited May 3, 2007 at 9:31 AM
Hi,

I'm considering how we could apply the validation application block to a domain driven project I work on. To get an overview of the product I watched your excellent video "Introducing the Validation Application Block " but it left me with one question related to Rulesets, essentially I want to know what I can do if I want one Ruleset to include all the rules from another Ruleset?

To illustrate why this might be important I'll come up with an example loosely based on our project. Our Customer class has many states (state pattern) such as New, WithCustomerSetupTeam, AwaitingCreditCardAuthorization and Active.

We might have no rules for a New Client but before it can move to the WithCustomerSetupTeam state we need to provide a Name/Address. This rule should then never be invalidated for the lifetime of the object, it will apply to the AwaitingCreditCardAuthorization and Active states.

Trying to do this with attributes will get very messy, my domain class is going to be rammed full of attributes unless I can specify that one Ruleset will include all rules from another Ruleset?

Thanks,

Colin Jack
May 3, 2007 at 2:12 PM
There is no way that I know of to say that one Ruleset includes all the rules from another Ruleset.

At a minimum it sounds like it would have been nice if a ValidatorAttribute allowed one to specify multiple Rulesets like:

[StringLengthValidator(1, 50, Rulesets="RuleSetA,RuleSetB,RuleSetC")]

This would avoid duplication if a validator belongs to several RuleSets.

You might be able to provide a similar behavior using a combination of Self-Validation and Rulesets, but I don't know of anyway to just declaratively provide the functionality.

Regards,

Dave

_____________________________

David Hayden
Microsoft MVP C#
May 3, 2007 at 3:45 PM
Edited May 4, 2007 at 7:57 AM
Yeah I feared that might be the case from the way the topic was dealt with in the video.

The idea of putting each ruleset in each rule seems a bit of a non starter, it means adding a ruleset/state will be very prone to errors. Adding states is not going to happen often but still. I'm also not too keen on the self validation idea, currently our rules are more like Specifications (Fowler/Evans) and i'd prefer to stick with that sort of approach (advantageous for the reasons Evans suggests that the pattern is useful).

It did surprise me that the whole Ruleset bit wasn't more key, in my experience validation/rules vary widely based on an objects state. I'd imagine people will end up running into this issue pretty quickly especially if they're trying to develop a complex domain model.

Ho hum, thanks for replying and clearing it up.
Sep 14, 2007 at 3:39 PM
I to wish there was a way to append rulesets together, so that it doesn't get too cumbersome. I'm not too keen with the approach of:

StringLengthValidator(1, 50, Rulesets="RuleSetA,RuleSetB,RuleSetC")

As now all imbedded classes would have to know about all the rules as well. The ability to combine multiple rulesets together would be much more advantageous as in the following example I could have the property of ID on a customer:

AllowNullValidator(Ruleset="AllowNull")
ValidatorComposition(CompositionType.Or, Ruleset="AllowNull")
NotNullValidator(MessageTemplate = "The value cannot be null", Ruleset="Default")
public string ID
{
get
{
return this.Id;
}
set
{
this.Id = value;
}
}

On a new customer call, where the ID could be null, I would combine the rulesets ('Default' and 'AllowNull') together and it would pass validation (assuming all other 'Default' rules on the class properties and imbedded classes pass), as my AllowNullValidator simply returns true. On any other call that needs a current customer ID, I would just use the 'Default' ruleset, which would require a non null value for the ID.

Sep 15, 2007 at 3:49 PM
Your need comes from the fact that you correlate your domain object logical state with the ruleset name.

What if you define a common ruleset name, let's say: ReachableCustomer. You then define your Name and Address validators based on that ruleset name.

You now just need to define a mapping between the Domain object state and the multiple rulesets to validate and launch multiple validations in a row.

I know a MultipleRuleSetValidator exists in the EntLibContrib project, it might help to some extent.

FYI, I still agree it could have been a nice and easy feature to support a comma separated list of rulesets the validator applies to.
Sep 16, 2007 at 2:55 PM
Check this post for a more detailed discussion on a validator I just created in order to do ruleset composition.
http://www.codeplex.com/entlibcontrib/Thread/View.aspx?ThreadId=15212