Validators supplied in the VAB
We're making great progress with the Validation Application Block in Enterprise Library 3.0, and one of the last remaining tasks is to make sure we include a compelling set of validators with the block. While it's very easy to build your own validator, we don't want everyone to need to build the same validators for each project just because we forgot to include something important.
Here's the set of validators we're currently planning to include - but it's not too late to set us straight if we've missed something! A few things to note are:
- All of these validators can be used from the API, attributes or configuration, although the syntax will vary across these mechansims.
- Some of the validators will use generic parameters, such as RangeValidator<T>. When used from the API, you will be able to use the validator with any type (subject to the generic parameter's constraints). However since you can't use generics in the same way from configuration or attributes, you'll only be able to use common primitive types from these mechanisms.
- All of our validators will include a Negate property, which will change the validator's behavior so that it will fail if the condition is met, rather than when it is not met. This will let you do things like use the "Contains Characters Validator" to check that a string does not contain characters.
First, here are the planned "basic" validators:
- Not Null Validator: Validates that a value is not null
- Range Vailidator (generic, supporting IComparable types): Validates that a value falls within a specified range. The range may be closed or open ended, and may be inclusive or exclusive.
- Relative DateTime Validator: Validates that a DateTime falls within a specified range, relative to now. The range may be closed or open ended, and may be inclusive or exclusive. For example, you could check if a date is between now and 100 years from now, or from 20 days ago to 4 days from now.
- String Length Validator: Validates that a string is of a certain length. May contain a minimum, a maximum or both.
- RegEx Validator: Validates that a string matches a specified regular expression. We'll also include support for "pre-canned" RegEx patterns for common things such as URLs, e-mail addresses, phone numbers etc.
- Contains Characters Validator: Validates that a string contains any, or all of the characters in a specified string.
- Type Conversion Validator: Validates that a string can be converted to a specific type (using a specific culture). For example, this could check that "6.32" can be converted to a Double, or "2007-02-09" can be converted to a DateTime.
- Enum Conversion Validator: Validates that a string can be converted to a value in a specified enum type. For example, this could check that "Blue" could be converted to a value in the Color enum.
- Domain Validator (generic): Validates that a value is included in a specified set, such as {"John", "Paul", "George", "Ringo"} or {2, 3, 5, 7, 11}. If the set only contains one value, this validator can be used to check for equality.
Next, here are our planned "composition" validators:
- And Composite Validator: Indicates that all of a set of child validators must pass
- Or Composite Validator: Indicates that just one of a set of child validators must pass.
Finally, here are our planned "value access" validators, which can be used to specify validation rules on complex objects:
- Property: Applies a validator to a property of an object
- Field: Applies a validator to a field of an object
- Method: Applies a validator to the result of a method of an object (can only be used for methods with no parameters and a non-void result, such as ToString()).
- Object: Specifies that a nested object needs to be validated by a particular rule set.
- Collection: Specifies that a nested collection of objects needs to be validated by a particular rule set.
Did we miss anything important?
Comments
Anonymous
January 09, 2007
Is there just a standard ComparisionValidator where you can say like 'greater than -1'.Anonymous
January 09, 2007
Kristian - you can do this with the RangeValidator (by only specifying one boundary).Anonymous
January 09, 2007
In addition to the And Validator and the Or Validator, what about something in-between (I don't have a good name now) which can validate that at least X conditions in the set are met. So, if you have 5 validators, and you want to be sure at least 3 of 5 are met (perhaps this is "good enough" quality for data input). Between those three, and the "Negate" property you mentioned, it should be possibly to express fairly complex validation when needed.Anonymous
January 09, 2007
How about a support for contexts, i.e. I have a user class and this user can actually be multiple types of user (standard, power, ultimate). I'd like the ability to specify validate for a given context e.g. ValidationMananger.Validate(User, Context) [please not I have not used any part of the block and the example is simply that]. So a bit like composite validator but you don't need to know which rules will fire....just that given the current context the right ones will fire. I'm sure there are other ways you could get around it....but just a suggestion.Anonymous
January 09, 2007
John - actually we already support this, through the concept of "rulesets" which are named collections of validators. The syntax is almost the same as what you specified: ValidationResults results = Validation.Validate(myUser, "Power");Anonymous
January 09, 2007
To be robust it should match the feature set of Peter Blum's validation package for ASP.Net. Multi-condition, centralized message panel to name a few.Anonymous
January 09, 2007
What about a CompareValidator that can reference another Field/Property/Method/etc... not to compare to a literal, but (for example) to compare two password entries.Anonymous
January 09, 2007
This is small thing, but you may consider this: DoesFileExist(filepath) and DoesFileNotExist. first check that the file path is not nothing and not empty then check the existence of the file (File.Exist).Anonymous
January 09, 2007
The comment has been removedAnonymous
January 10, 2007
Two points:
- Unless I'm missing something the proposed architecture can't handle co-occurance constraints (e.g. "If Customer.OccupationType = 'Employed' Then Customer.Occupation.Address is required").
- I'm not sure I want my validation logic in code in the first place. It seems like the better place for this is in a rules engine which your entities can call out to validate themselves. Validation rules change. They change often enough that I'd rather re-publish a rules update then re-compiling/deploying code. Finally, a rules engine has no problem with point 1) above.
Anonymous
January 10, 2007
Quote To be robust it should match the feature set of Peter Blum's validation package for ASP.Net. end quote If not this, this validation should offer one-to-one mapping to asp.net validation controls. So that I can programmaticaly inject this validation controls counterpart asp.net control to my page easily. If I can do that, I will have best of both worlds. Defense in depth. My services will be validated also my client will have javascript support.Anonymous
January 10, 2007
Tom, How about handling semi-mandatory data based on certain other input value conditions? -RaviAnonymous
January 10, 2007
What about Parameter validation. Often when you write methods you want to do simple checks to ensure that the values passed in are correct or in a certain range. It would be awesome to be able to drop for example a [NotNullValidator] a parameter to a method rather than having to manually code the checks. Another place this could be used is in a class constructor.Anonymous
January 10, 2007
I totally agree with Glenn's comment about Parameter Validation; that would be one of the biggest benefits in my mind. If you could write; public void GetSomething( [NotNullValidator] string myName, [RangeValidator<int>(1, 100) int myAge) ... the boiler-plate code at the start of each method would be so much simpler, and code requirements and intentions would be more obvious from method definitions.Anonymous
January 10, 2007
The comment has been removedAnonymous
January 11, 2007
I was thinking the same thing a Jarle. The benefit would be to seperate out the common concerns for validating parameters as well as to remove redundant coding.Anonymous
January 12, 2007
I have a quick comment on the "composition" validators (to me I would call this a rule set - but you're already using that term) Rather than use "And Composite Validator" and "Or Composite Validator" I would suggest using language and terms similar to the WaitHandle methods (which in my mind is conceptually the same thing) http://msdn2.microsoft.com/en-us/library/system.threading.waithandle_methods.aspx So the composite validators would be named "AndAny Composite Validator" "AndAll Composite Validator" Clearly the negate functionality would still apply. If I can compose a composite validator with other child composite validators than I can have some really extensive branching logic checks. sweet.Anonymous
January 12, 2007
Side note: To help people provide good feedback you should have in the first place clearly defined a borderline between "simple" validation and "complex" rules engine. This would be ability of rules engines to perform not only checks but some actions? If this is it then you still need to provide means for complex branching logic as in examples above. Personally, i think method's parameters validation is a must. Also, it would be really great if VAB will contain some kind of connectors or adapters to ASP.NET validation framework. This will add a lot of value to your work.Anonymous
January 14, 2007
Parameter validation is defiantly a must. I think this project performs some kind of parameter validation http://www.codeplex.com/ValidationFramework Although it does not do the AND/OR style of composite validators.Anonymous
January 17, 2007
Thanks for all the feedback. We're planning to add a "Member comparison validator" to address the scenario rasied a few times here, although it won't make it into this month's CTP. We're also going to ship integration adapters for Winforms and ASP.NET in the next CTP, and we'll add WCF support before we release. thanks TomAnonymous
January 17, 2007
Our team is hard at work putting the finishing touches on the January 2007 CTP of Enterprise LibraryAnonymous
January 23, 2007
How about cross field validation? Things like validateCityInState(objCity, objState) will be a nice addition. Of course, both of them will be in the same class.Anonymous
January 23, 2007
Benson - we've implemented a Property Comparison Validator (post Jan CTP) that lets you compare two properties on the same type using operators such as =,!=,<,>,<= and >=. It doesn't let you plug in custom algorithms or strategies like City In State suggestion, but it would be simple enough to build your own validator that followed a similar approach. TomAnonymous
January 26, 2007
I still miss a compare validator attribute which enables the validation of one property against the other. For Example I want my enddate to be greater than the startdate. for example. public DateTime StartDate {get;set;} [ComparePropertyValidator("StartDate",CompareOperator.GreaterThan)] public DateTime EndDate {get;set;] This would be possible if the Object To Validate is passed with the Attribute.Validate() method. PatrickAnonymous
January 26, 2007
One thing that isn't clear to me is how you should add errormessages to an attribue. I hate placing hardcoded constant strings in the code. I would like to use a resource file for maintaining the errormessages (globalization). One way to do this is to add a configuration setting specifying the resource file to use for a specific ruleset. You could then use a naming convention for naming the keys in the resource file. for example Key:NotNullOrEmptyString_myclass_myProperty Value: the field 'MyField' is required. This way you don't need to supply the attribute itself with an errormessage. PatrickAnonymous
January 26, 2007
Thanks Patrick. Re cross-property comparisons: as per my comment above, this has been implemented almost exactly as you described, however it was done after the January CTP release so you won't see it until the next drop. Re resources: We already support externalization of error messages, although not quite in the way you described. When defining validators through either attributes or configurations, you can specify either a hard-coded message template, or you can specify a resource name and resource assembly that contains the message. This should work in the January CTP. TomAnonymous
February 11, 2007
I did not notice any "Validate only if filled" Validators for optional items. For example, in an ASP.NET application, we sometimes have optional parameters passed to a page. It'd be nice to have a vaidator on these types that we can call all the time, but the validator only checks the values if the parameter is actually filled.Anonymous
February 12, 2007
You can accomplish this with the OrCompositeValidator and the [IgnoreNulls] attribute. TomAnonymous
February 13, 2007
"To help people provide good feedback you should have in the first place clearly defined a borderline between 'simple' validation and 'complex' rules engine. This would be ability of rules engines to perform not only checks but some actions?" Personally, I prefer something like this, which can do both 'simple' validation and 'complex' rules with actions: http://www.activesharp.com . The approach also lends itself very well to cross-field validation.Anonymous
February 20, 2007
What if you want to use the date validator and the Date must be greater then Today? So not a specific date.Anonymous
February 20, 2007
Wesley - that's what the Relative DateTime Validator is for. TomAnonymous
February 21, 2007
Is there an easy way to validate multiple objects of different class type in one pass, and return all of the error messages in one go? i.e. in an architecture where the web layer communicates with the business layer via a webservice, I'd like to limit the number of calls to the back end. Also, Without using reflection, it is not too straightforward to call validate on multiple objects, collate all of the validationResults and an overall IsValid result, and return a final value. Also, given that a lot of reflection is probably used in the implementation of this, how well does the VAB perform with a large number of users and a large number of complex validations?Anonymous
February 21, 2007
Hi Hitch - The ObjectValidator lets you specify that the block should follow references from one type to another and combine all of the validation results. So if you have several different objects you want to validate together, the easiest approach would be to build a new class that is an umbrella for all of the other objects and use the ObjectValidator to wire them all together. Re performance - yes we do use reflection at construction time but we've optimized things where possible. Hopefully the performance is acceptable for the functionality provided in most real world situations. TomAnonymous
March 09, 2007
When creating validators in code how do you tell it what property to validate? Can you give me a simple example using VB?Anonymous
March 09, 2007
Hi Tyler - While you could go and set up a big graph of validators involving the PropertyValueAccessValidator (which is what happens under the covers when validators are built from attributes or configuration) I wouldn't recommend this approach if you want to do it all from code. Instead you can just call the validator and pass it the value of the property, eg: Dim v As New StringLengthValidator(5, 10) Dim results As ValidationResults = v.Validate(myCustomer.FirstName)