Validation Block Inheritance with custom validator or SelfValidation

Topics: Validation Application Block
May 13, 2009 at 9:01 PM

I have a base class with validation attributes on some of the properties as well as a custom validator attribute for the class as a whole. When I inherit from this class and say Validator.Validate(inheritedClass), it runs inherited and base property attribute validations fine, but it does not run the base classes custom validators at all. I also tried adding a <HasSelfValidation> attribute and a <SelfValidation> function on the same base class and those are not run either. All of the base validations (including the SelfValidation and custom) work fine when called with Validator.Validate(of baseClass)(inheritedClass).

The custom validators and SelfValidation validators are part of the inherited class, why are those validations not being called?  Any help is appreciated. Thanks!

Code is below.

Thanks!

 

Imports Microsoft.Practices.EnterpriseLibrary.Validation

Imports Microsoft.Practices.EnterpriseLibrary.Validation.Validators

 

 

<PersonValidator()> _

<Validators.HasSelfValidation()> _

Public Class Person

 

  <Validators.StringLengthValidator(5, messagetemplate:="P1: Person.Name was too long")> _

  Public Property Name() As String

    Get

      Return "Person.Name's value"

    End Get

    Set(ByVal value As String)

 

    End Set

  End Property

 

  <Validators.SelfValidation()> _

  Public Sub ExtraValidation(ByVal results As ValidationResults)

    results.AddResult(New ValidationResult("P2: Extra Validation failed", Me, "", "", Nothing))

  End Sub

 

End Class

 

Public Class Employee

  Inherits Person

 

  <Validators.StringLengthValidator(5, messagetemplate:="E3: Employee.Position was too long")> _

  Public Property Position()

    Get

      Return "Employee.Position's value"

    End Get

    Set(ByVal value)

 

    End Set

  End Property

 

End Class

 

 

Public Class PersonValidator

  Inherits Validator(Of Person)

  Public Sub New()

    MyBase.New("", "")

  End Sub

  Protected Overrides ReadOnly Property DefaultMessageTemplate() As String

    Get

      Return ""

    End Get

  End Property

  Protected Overloads Overrides Sub DoValidate(ByVal objectToValidate As Person, ByVal currentTarget As Object, ByVal key As String, ByVal validationResults As Microsoft.Practices.EnterpriseLibrary.Validation.ValidationResults)

    validationResults.AddResult(New ValidationResult("P4: PersonValidator.DoValidate has a validation problem", objectToValidate, "", "", Nothing))

  End Sub

 

End Class

 

Public Class PersonValidatorAttribute

  Inherits ValidatorAttribute

 

  Protected Overrides Function DoCreateValidator(ByVal targetType As Type) As Validator

    Return New PersonValidator()

  End Function

End Class

 

May 13, 2009 at 9:04 PM

Here is the test code with results in comments:

  <TestMethod()> _

  Public Sub TestPersonValidations()

    Dim emp As New Employee

    Dim result = Validation.Validate(Of Person)(emp)

    Assert.AreEqual(result.Count, 3) ' fine: 3=3. result has: P4, P1, P2

  End Sub

 

  <TestMethod()> _

  Public Sub TestEmployeeAndPersonValidations()

    Dim emp As New Employee

    Dim result = Validation.Validate(emp)

    Assert.AreEqual(4, result.Count) ' fails: 4<>2. result has E3, P1

  End Sub

 

 

May 14, 2009 at 4:37 AM

It's because in the first method the Validation specifically looks for Validators for Person type.  It won't look for validators for type Employee.  The second validation infers the type of the object you passed in the Validate method which is of type Employee so it goes looking validators for it and does not include the Person validators. 

 

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

May 14, 2009 at 1:51 PM
Edited May 15, 2009 at 1:54 PM

But it actually is supposed to inherit the validations from the base (according to: http://msdn.microsoft.com/en-us/library/dd203292.aspx) and it in fact does properly inherit the base's PROPERTY validation attributes correctly. This is proven in my second test where it is validating it as an Employee and still includes the "P1: Person.Name was too long" in the ValidationResults. Note that saying:  Validation.Validate(of Employee)(emp)does returns the same results as test 2 as you mentioned.

So it inherits the validation attributes on properties within the base class, but not the validation attributes on the base class itself. This seems like an inconsistency (or bug), as I would expect inheritance to either work or not work (ideally just work!)

And unfortunately, if I try to hook up the inheritance myself by calling the base's validation within the child (so I added a HasSelfValidation attribute and the following method on Employee:)

  <Validators.SelfValidation()> _

  Public Sub ExtraValidation2(ByVal results As ValidationResults)

    results.AddAllResults(Validation.Validate(Of Person)(Me))

  End Sub

then I end up with E3, P1, P4, P1, P2, P2, which has duplicate ValidationResults for the Person validations P1, P2. Oddly enough, it only comes back with one P4 (custom validator on the base class) result, which makes no sense to me given that it returns two P2 results (self validation on the base) and I think is another odd inconsistency in how it works... but apparently having the <HasSelfValidation> attribute on Employee causes it to execute not only the SelfValidation in Employee (ExtraValidation2) but also the base's SelfValidation (ExtraValidation).

Any ideas on how to make validator inheritance work in the way we would expect (i.e. when inheriting from a base, the inheriting class gets the bases validators by default)?

 Thanks,
- pamo

 

May 18, 2009 at 6:00 AM

Yes, you are right, my mistake, sorry about that.  You seem to hit a bug.  Have you logged it already in the tracker?  I'm afraid you already have done the workaround and that is by trigerring the other call validation using a self validation method.  The duplicated results may be removed by examining the duplicated keys.  I'll see if I can think of another way to get around this one and let you know.

 

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

May 20, 2009 at 5:06 PM

Ok thanks. I just logged it in the tracker now as issue: 22518.

Hopefully something will be figured out as solid validation inheritance is pretty important to most OO models.