Extending ValidationBase to Validate Properties of Type ValidationBase

A couple of days ago I got an e-mail from Maarten van der Lee with some code that can be used in my Validation Framework of my N-Layer Design article series to validate sub properties whose type is a ValidationBase as well. This can be useful if you want to present a full list of validation errors for an object and its properties.

Extending ValidationBase

Consider the ContactPerson class from my article series on N-Layer design. This class has an Addresses collection that contains zero or more addresses. But what if the ContactPerson only had a single address whose type is Address (which inherits ValidationBase)? In that case, when validating the ContactPerson, you may also want to validate the Address in one fell swoop and show a list of errors to your users like this:

  • Enter your first name
  • Enter your zip code
  • Choose an address type

Fortunately, with just a bit of code, this is easy to implement. In the ValidationBase class, add the following code near the end of the Validate method, just before the return statement:

public virtual bool Validate(bool clearBrokenRules)
{
  ...
  foreach (PropertyInfo property in properties)
  {
    ValidationBase vbase = property.GetValue(this, null) as ValidationBase;
    if (vbase != null && !vbase.Validate())
    {
      foreach (BrokenRule brokenRule in vbase.BrokenRules)
      {
        BrokenRules.Add(new BrokenRule(string.Format("{0}.{1}", 
             property.Name, brokenRule.PropertyName), brokenRule.Message));
      }
    }
  }  
  return (BrokenRules.Count == 0);
}

When you run this code, the Address property is now validated as well. The BrokenRules collection of the ContactPerson now also contains broken rules for the address in the format ParentPropertyName.SubPropertyName, ValidationMessage. So, for example for an Address property whose zip code is not valid, you get an error like:

Address.ZipCode, "Enter your zip code"

You can use these validation rules to build up a list in the UI similar to the way I have done in my article series on N-Layer design.

The cool thing about this solution is that it works recursively. If the Address instance in turn contains another ValidationBase property (like LocationOnEarth) you would end up with a broken validation rule like Address.LocationOnEarth.Long, as shown in the following screen shot of the debugger:

Screen shot of the debugger showing the broken validation rules for the nested objects.

Thanks for the tip, Maarten. I'm sure this comes in handy when dealing with more complex object hierarchies.

Download Files

The modified ValidationBase class (C# only)


Where to Next?

Wonder where to go next? You can read existing comments below or you can post a comment yourself on this article .


Consider making a donation
Please consider making a donation using PayPal. Your donation helps me to pay the bills so I can keep running Imar.Spaanjaars.Com, providing fresh content as often as possible.



Feedback by Other Visitors of Imar.Spaanjaars.Com

On Wednesday, April 29, 2009 12:57:39 PM Maarten van der Lee said:
Maybe it is even better to use a special attribute for these kind of properties. There is, for instance, no point in validating the address-class if the address itself may be null.
On Monday, May 11, 2009 8:30:18 PM Imar Spaanjaars said:
Hi Maarten,

Would a NotNullOrEmpty attribute on the Address do the trick? E.g., that checks whether the item is null. If it isn't, the sub validation kicks in.

Imar
On Tuesday, August 25, 2009 2:25:15 PM Hugo Santos said:
Hi Imar, thanks for your great work!
I have a question, what is the main advantage of your validation framework when compared to Microsoft Enterprise Library(4.1)?
Thanks in advance
On Tuesday, August 25, 2009 6:38:36 PM Imar Spaanjaars said:
Hi Hugo,

I prefer the simplicity of use and configuration of my solution over that of the EL. Obviously it all depends on what you're used to, and what you need to use it for. In many cases, EL is probably a better choice. Try both out and see what you like...

Cheers,

Imar
On Thursday, October 22, 2009 7:02:20 PM Eduardo said:
Hi, who implement? I´m novice
On Thursday, October 22, 2009 9:50:41 PM Imar Spaanjaars said:
Hi Eduardo,

Heuh? What?

Imar
On Wednesday, June 08, 2011 7:52:24 AM Jay said:
Hi Imar,
i just noticed the new validation code and couldn't get it to work with the e-mail address for example: and i believe the reason is because this is comes back always as nothing:
ValidationBase vbase = property.GetValue(this, null) as ValidationBase;
since the EmailAddress is a type BusinessBaseCollection which is derrived from ValidationCollectionBase. or am i missing something?
so it seems that the code above needs modification to loop through the emailaddress collection first and then to the code above...
thanks.
On Wednesday, June 08, 2011 2:02:28 PM Imar Spaanjaars said:
Hi Jay,

Yes, it does need modification. The code above is designed to validate direct properties, not collections. Not too hard to implement though.

Alternatively, you can override Validate in ContactPerson as described in the initial article and validate collections there.

Cheers,

Imar
On Thursday, June 09, 2011 8:15:09 AM Jay said:
Hi Imar,
Thank you for confirming that. here is what i did to make it work please let me know if there is a better easier way.

**************replaced the above code with the below *********
For Each prop As PropertyInfo In properties

.......
            Dim propValue As Object = prop.GetValue(Me, Nothing)

            If propValue  IsNot Nothing Then
                If IsTypeDerivedFromGenericType(propValue.GetType(), GetType(ValidationCollectionBase(Of ValidationBase))) Then 'InheritsOrImplements(test.GetType(), GetType(ValidationBase))

                    For Each aprop In prop.GetValue(Me, Nothing)
                        Dim vbase As ValidationBase = TryCast(aprop, ValidationBase)
                        If vbase IsNot Nothing AndAlso Not vbase.Validate() Then
                            For Each brokenRule As BrokenRule In vbase.BrokenRules
                                'If BrokenRules IsNot Nothing Then
                                BrokenRules.Add(New BrokenRule(String.Format("{0}.{1}", prop.Name, brokenRule.PropertyName), brokenRule.Message))
                                ' End If
                            Next
                        End If
                    Next
                End If
            End If


and added a new Function that finds the base class and do a comparison:

    Public Function IsTypeDerivedFromGenericType(typeToCheck As Type, genericType As Type) As Boolean
        If typeToCheck = GetType(Object) Then
            Return False
        ElseIf typeToCheck Is Nothing Then
            Return False
        ElseIf typeToCheck.IsGenericType AndAlso typeToCheck.GetGenericTypeDefinition().Name = genericType.Name Then
            Return True
        Else
            Return IsTypeDerivedFromGenericType(typeToCheck.BaseType, genericType)
        End If
    End Function


Please let me know if there is a better way thanks.
On Thursday, June 09, 2011 8:18:01 AM Jay said:
I forgot to mention,
with the above code now all i have to do is call:
myContact.validate()

whcih goes down and drills though all properties including the collection of ValidationCollectionBase like EmailAddress and PhoneNumbers and all ... and adds the BrokenRules to the list of all BrokenRules.

Cheers.
On Thursday, June 09, 2011 10:48:37 AM Imar Spaanjaars said:
Hi there,

I haven't tested it but can't you use TryCast to see if you can cast the property to a ValidationCollectionBase? E.g.

TryCast(item.Property.GetValue(Me, Nothing), ValidationCollectionBase(Of ValidationBase))

Then you don't need your helper method.

Cheers,

Imar
On Friday, June 10, 2011 4:19:57 PM jay said:
Hi,
Yah i thought about that and tried it but it always returns nothing... for whatever reason.....


and when i stepped down throught the code using the debugger i noticed that base Name is the same but the fullName of the type is not which fails the tryCast.. even in my helper function i had to limit the comparason to just .name instead the whole Type.

Talk Back! Comment on Imar.Spaanjaars.Com

I am interested in what you have to say about this article. Feel free to post any comments, remarks or questions you may have about this article. The Talk Back feature is not meant for technical questions that are not directly related to this article. So, a post like "Hey, can you tell me how I can upload files to a MySQL database in PHP?" is likely to be removed. Also spam and unrealistic job offers will be deleted immediately.

When you post a comment, you have to provide your name and the comment. Your e-mail address is optional and you only need to provide it if you want me to contact you. It will not be displayed along with your comment. I got sick and tired of the comment spam I was receiving, so I have protected this page with a simple calculation exercise. This means that if you want to leave a comment, you'll need to complete the calculation before you hit the Post Comment button.

If you want to object to a comment made by another visitor, be sure to contact me and I'll look into it ASAP. Don't forget to mention the page link, or the QuickDocId of the document.

For more information about the Talk Back feature, check out this news item.