Validation Block and Nested Object

Topics: Validation Application Block
Feb 2, 2010 at 2:13 AM

Hi all,

I have a class and other class as List collection nested inside, please see my sample code below. I also applied validation attribute to the nested class' property. But when I call Validation.Validate() function, the nested class is not actually validated.

Is there a way I can force validation block 4.1 to go deep into nested objects?

namespace ConsoleApplication1 {
	class Program {
		static void Main(string[] args) {
			Class1 cls1 = new Class1();
			cls1.MyNested = new List<Class2>();
			cls1.MyNested.Add(new Class2 {
				Address = "A"
			});

			ValidationResults results = Validation.Validate<Class1>(cls1);
			Console.ReadLine();
		}
	}

	public class Class1 {
		[StringLengthValidator(3, 10, MessageTemplate = "some message 1")]
		public string Name {
			get;
			set;
		}

		public List<Class2> MyNested {
			get;
			set;
		}
	}

	public class Class2 {
		[StringLengthValidator(10, 20, MessageTemplate = "some message 2")]
		public string Address {
			get;
			set;
		}
	}
}

Feb 2, 2010 at 2:26 AM

Decorate it with the ObjectCollectionValidator attribute.  For simple nested types, use the ObjectValidator attribute.

 

Sarah Urmeneta
Global Technology and Solutions
Avanade, Inc.
entlib.support@avanade.com

Feb 2, 2010 at 2:30 AM

How about nested object collection, like in my sample?

Feb 2, 2010 at 2:31 AM

Use the ObjectCollectionValidator

 

Sarah Urmeneta
Global Technology and Solutions
Avanade, Inc.
entlib.support@avanade.com

 

Feb 2, 2010 at 11:40 AM

Thanks a lot!

Feb 5, 2010 at 2:11 AM

I think I encoutered a more complicated situation. I created following code sample to illustrate my issuse. I have a collection with objects derived from a base class, and I set validation rule to one of the inherited class (ClassExt2 in this case). The troubled part is the red code below how to define type of object to validate.

If I set value to "BaseClass" then nothing is got validated, if I set value to "ClassExt2" then I got 2 validation error:

  • Message = "The element in the validated collection is not compatible with the expected type.". I think this is caused type mis-match of ClassExt2 against ClassExt1 in the collection while application block iterates through every single item.
  • Message = "some message 1". This is what I need.

Is there a way I can supress validation block not to check non-matched object type?

	class Program {
		static void Main(string[] args) {
			Class1 cls1 = new Class1();
			cls1.MyNested = new List<BaseClass>();
			cls1.MyNested.Add(new ClassExt1 {
				PropertyA = "A"
			});
			cls1.MyNested.Add(new ClassExt2 {
				PropertyB = "A"
			});

			ValidationResults results = Validation.Validate<Class1>(cls1);
			Console.ReadLine();
		}
	}

	public class BaseClass {
		public string SharedProperty {
			get;
			set;
		}
	}

	public class ClassExt1 : BaseClass {
		public string PropertyA {
			get;
			set;
		}
	}

	public class ClassExt2 : BaseClass {
		[StringLengthValidator(3, 10, MessageTemplate = "some message 1")]
		public string PropertyB {
			get;
			set;
		}
	}

	public class Class1 {
		[ObjectCollectionValidator(typeof(ClassExt2))]
		public List<BaseClass> MyNested {
			get;
			set;
		}
	}
Feb 5, 2010 at 4:33 AM

Hi,

So far I can't still find a way to supress that. I'll continue with the investigation and let you know if there is a workaround.

Valiant Dudan
Global Technology and Solutions
Avanade, Inc.
entlib.support@avanade.com

Feb 8, 2010 at 5:20 AM

The ObjectCollectionValidator doesn't support this scenario.  However, you can create your custom object collection validator.  Basically, the code is the same but instead of creating the Validator object in the constructor, you would create a different Validator object for every object in the list.  Thus, in the existing DoValidate method, instead of this:

if (this.targetType.IsAssignableFrom(element.GetType()))
{
     this.targetTypeValidator.DoValidate(element, element, null, validationResults);
}

you'll need to do this:

if (this.targetType.IsAssignableFrom(element.GetType()))
{
    Validator validator = ValidationFactory.CreateValidator(element.GetType());
    validator.Validate(element, validationResults);
}

 

Sarah Urmeneta
Global Technology and Solutions
Avanade, Inc.
entlib.support@avanade.com

Feb 8, 2010 at 11:43 PM

Thanks, I created my own validation class based on existing ObjectCollectionValidator.cs class, and made following changes

						if (element != null) {
							if (this.targetType.IsAssignableFrom(element.GetType())) {
								// reset the current target and the key
								//this.targetTypeValidator.DoValidate(element, element, null, validationResults);
								Validator validator = ValidationFactory.CreateValidator(element.GetType());
								validator.Validate(element, validationResults);
							} /*else {
								// unlikely
								this.LogValidationResult(validationResults,
									"The element in the validated collection is not compatible with the expected type.",
									element,
									null);
							}*/
						}
I seems to be working, even I set validation type to BaseClass.... Very interesting.
Feb 10, 2010 at 12:48 AM

Yes, as it creates a validator based on each collection member's specific type whereas in the ObjectCollectionValidator, it only creates one validator for all the collection members based on the type you specified in the attribute/config.

 

Sarah Urmeneta
Global Technology and Solutions
Avanade, Inc.
entlib.support@avanade.com

Feb 11, 2010 at 6:19 AM

Just an update here, this is already addressed in version 5.0, you can try out the beta release.  You just need to decorate your property with the ObjectCollectionValidator attribute without specifying the target type.

 

Sarah Urmeneta
Global Technology and Solutions
Avanade, Inc.
entlib.support@avanade.com