VAB: is validating recursive object graphs not supported ?

Topics: Validation Application Block
Feb 27, 2007 at 1:27 PM
Edited Mar 1, 2007 at 8:51 AM
I have a domain object that is hierarchical and self-referencing, e.g. a folder object can contain a collection of folder objects in addition to folder metadata and a collection of files. If I use ObjectCollectionValidator(typeof(Folder)) on the folder's folder collection, the call to Validation.Validate(rootFolder) silently kills the unit-test. No exception, even if I have 'break when CLR exception is thrown' turned on in VS2005, thus I expect this to be a stack overflow of some sort.

The crash happens in Validation.cs line 31 during:
Validator<T> validator = ValidationFactory.CreateValidator<T>();

Bug, feature, my mistake or just not supported ?
Mar 1, 2007 at 9:08 AM
Edited Mar 1, 2007 at 9:30 AM
I have done some further testing by using XML config for the object with the recursive collection instead of attributes. Still the same problem, just dies - no exception. If I just comment out the <validator type=ObjectCollectionValidator>, the validation engine works and validates the other class members.

Any ideas ? The config section was built using the config editor and looks ok. There is another non-recursive ObjectCollectionValidator in there also, which works fine.
Mar 1, 2007 at 11:48 AM
Edited Mar 1, 2007 at 1:15 PM
To fix this problem, I made a modification to ValidatorBuilder.cs to prevent entering a loop for recursive/self-referencing object graphs by introducing a "processed types" list that is used throughout the validator building process. The fix is based upon that it is safe to skip building yet another validator for a type (class) that has aleady been built, as the class members and the related rules do not change. Thus once added to the set of validators, there is no need to add the rules once more.

Now all that is left is to check if the interpretation of the built validator rule set for an instance of an object graph works correctly.

//KJELLSJ: THREAD STATIC
ThreadStatic()
static private List<string> _processedObjectTypeList = new List<string>();


The CreateValidatorForValidatedElement method now looks like this:

protected Validator CreateValidatorForValidatedElement(IValidatedElement validatedElement, CompositeValidatorBuilderCreator validatorBuilderCreator)
{
IEnumerator<IValidatorDescriptor> validatorDescriptorsEnumerator = validatedElement.GetValidatorDescriptors().GetEnumerator();

if (!validatorDescriptorsEnumerator.MoveNext())
{
return null;
}

CompositeValidatorBuilder validatorBuilder = validatorBuilderCreator(validatedElement);

do
{
//KJELLSJ: BREAK RECURSIVE LOOP
if(validatorDescriptorsEnumerator.Current is ObjectCollectionValidatorData)
{
string typeName = validatedElement.TargetType.FullName;
if( _processedObjectTypeList.Exists(delegate(string s){return s.Equals(typeName);})) continue;
_processedObjectTypeList.Add(typeName);
}

Validator elementValidator = validatorDescriptorsEnumerator.Current.CreateValidator(validatedElement.TargetType);

validatorBuilder.AddValueValidator(elementValidator);
}
while (validatorDescriptorsEnumerator.MoveNext());

return validatorBuilder.GetValidator();
}
Mar 1, 2007 at 2:03 PM
Well, no surprise: the interpretation of the object graph instance is done by recursively walking the built rule tree, not by walking the object graph. Thus, the complete object graph is not validated, it stops where I broke the recurive loop when building the validator tree.

The validation engine should be modified to use a dictionary of validation sub-trees, one sub-tree for each distinct type of ObjectCollectionValidator. I.e. build one sub-tree for ObjectCollectionValidator(typeof(Folder)) and use that sub-tree for validating all instances of that collection type in the object graph. Imposing a 1-to-1 mapping requirement between the logical rule set and the physical object graph is just too limiting for a broken rules engine.

The same mechanism should also be applied to ObjectValidator.