Feedback on combining rules from attributes and config

Topics: Validation Application Block
Jan 3, 2007 at 9:29 PM
We'd like to get your feedback on the way that the Validation block in the December CTP combines rules from attributes and configuration.

Currently, the ValidationFactory and Validator facades provide a few different entrypoints, eg:

CreateValidatorFromAttributes -> only looks at rules defined in attributes
CreateValidatorFromConfiguration -> only looks at rules defined in configuration
CreateValidator -> combines all of the validators found in both attributes and configuration

The rationale for this is that the combined approach provides the most flexibility, as you can define rules in code but later add additional rules through configuration. The attribute- and config-only approaches give you more control (eg if you provide rules in attributes you know they can't be changed without recompiling the code) and better performance (as we don't need to look in so many places).

Do you think these options are all desirable? Which ones would you be likely to use? Would you prefer an approach (either as well as, or instead of the current model) where configuration-based rules, if present, would replace rather than augment the attribute-based rules?

Looking forward to hearing your thoughts on this.
Jan 4, 2007 at 12:00 AM
We use the attribute validator configuration as much as possible because (for us) it makes the most sense to have the validator information embedded right in the business object. For any special validations that are based on special logic or other status indicators then we add the validators at runtime. Having both capabilities is very critical for us. The config file validation settings are interesting but I haven't seen enough things about them to switch over from using attributes.
Jan 4, 2007 at 5:07 PM
I think all 3 approaches that you've outlined are necessary to provide the most flexibility for consumers of the block - as well as the ability to add, remove, and modify rules at runtime.

I haven't looked at the Validation Block source or design in detail - can rules be uniquely identified within the context of a rule container or application, using a well-known name? If so then it might be useful to provide a cascade model, so that named rules defined in attributes can be overridden by named rules defined in configuration that have the same identifier.

I can think of several scenarios where it would be useful to define a default rule using an attribute, then modify or remove the rule using the configuration.

Also, are you going to add a database loader for validation rules, using the Data Access block? It would be great to have the option of storing rules in a table, and you could provide a 2nd-level of cascade as well, so:

Database rule --> overrides Configuration rule --> overrides Attribute rule

Just some thoughts. Really looking forward to using this block in my applications.
Jan 5, 2007 at 12:34 AM
Personally, I will stick to using one or the other and not both. The scenario where you combine rules from both the configuration file and attributes always felt a bit odd to me. My gut is that one would put the rules in either one place or the other for maintainability reasons.

The only time I thought I might combine is when ValidatorAttributes were used from the beginning and one of two scenarios occurred. One, I didn't have access to the source code to apply ValidatorAttributes to the existing ones and thus needed to add new rules to the config file as a last resort. Or, I wanted to deploy a quick rule in the config file to avoid compiling the source code as a sort of quick interim fix until I had a chance to add a ValidatorAttribute in a controlled fashion.

So, I could see the use for the combination, but for me it would be for temporary reasons.

The options of not combining and just having one overriding the other would be good when transitioning from one configuration to the other. It would be useful in unit tests during transition as long as you could control programmatically the relationship: combine, use config only, use attributes only.

It might also be useful to have a setting in the config file (and programmatically if possible) that specifies whether validation is on or off, sort of like we have logEnabled filter in the logging application block. I didn't see one in my initial research.




David Hayden
Microsoft MVP C#
Feb 20, 2007 at 1:23 AM
Not sure if this is the correct place to post,

Have a situation where I need to have the ability to calculate age of a ‘customer’ data contract, using the current date time as the bench mark.

For example, the below code decorates ‘DateOfBirth’ property of the customer. However, its not suitable because of the restrictions attributes apply.
DateTimeRangeValidator(DateTime.Now.AddYears(18).ToString(CultureInfo.CurrentCulture), DateTime.Now.AddYears(110).ToString(CultureInfo.CurrentCulture))
public Nullable<DateTime> DateOfBirth
get { return _dateOfBirth; }
set { _dateOfBirth = value; }

I was hoping you could point out possible ways to:
1) Allow for null able date time.
2) Set the Date time dynamically.
3) How would this done in a configuration file.
Possible Solution
Create custom validator that encapsulates the bench mark.

David, great samples on your blog, but would be helpful if you could update them :), configuration settings.

Help much appreciated
Sonny Mal
Feb 20, 2007 at 2:01 AM
Hi Sonny -

We built a RelativeDateTimeValidator that does exactly what you suggested. I can't remember if it made it into the January CTP, but it's definitely built now and will surface in the next CTP if it's not there now. Here's what it looks like in attribute form:

RelativeDateTimeValidator(-120, DateTimeUnit.Year, -18, DateTimeUnit.Year, Ruleset="RuleSetA", MessageTemplate="Must be 18 years or older.")

Feb 20, 2007 at 3:38 AM
Hi Tom,

Great, differently solves the scenario described above. How long do we have to wait until the next CTP version due :)

Sonny M

Feb 20, 2007 at 4:06 AM
One more question, will the date time validator handle nullable types, I modified the 'Microsoft.Practices.EnterpriseLibrary.Validation.Validator<T>' class so that there is a extra check within in the 'DoValidate' method.

if (objectToValidate != null)
this.DoValidate((T)objectToValidate, currentTarget, key, validationResults);

Not 100% if this is the correct solution, but it works for me.

Sonny M
Feb 20, 2007 at 4:18 AM
Hmm, Ignore my last two post.
Tom: RelativeDateTimeValidator is in the Jan CTP .

Sonny M
Feb 20, 2007 at 4:51 AM
If you want to consider null as a valid value when the validator inherently does not, you can either add the IgnoreNulls attribute, or in config you can create a Or validator and nest the original validator with a negated Not Null validator.