This month, I have decided to introduce you to the Validation Application Block (if you are not already). This is part of the Microsoft Enterprise Library which is a set of blocks emerging from the Patterns and Practices group. The latest version (version 4.1) was released in October 2008 and the next version is expected next Fall.
I personally discovered it recently and cannot live without it anymore.
It was also the topic of my presentation at Montréal CodeCamp held May 30th.
What is the Enterprise Library?
Instead of trying to propose my own definition, I will do the lazy guy and paste a definition straight from Microsoft website: “The Microsoft Enterprise Library is a collection of reusable software components (application blocks) designed to assist software developers with common enterprise development cross-cutting concerns (such as logging, validation, data access, exception handling, and many others). Application blocks are a type of guidance; they are provided as source code, test cases, and documentation that can be used "as is," extended, or modified by developers to use on complex, enterprise-level line-of-business development projects.”
The official home of the Enterprise Library is http://msdn.microsoft.com/en-ca/library/dd203099.aspx. The team also maintain a CodePlex page at http://www.codeplex.com/entlib.
Installation
If you install the latest version (4.1 – October 2008), you will need to have VS2008 SP1 already installed. You will find the latest version available for download from http://www.microsoft.com/downloads/details.aspx?familyid=1643758B-2986-47F7-B529-3E41584B6CE5&displaylang=en. It is a 30 MB .msi file to download which contains the installer for all the blocks.
One funny thing I found during download is that the Express edition does not seem to support the Enterprise library. The system requirements specifies “standard editions and above”. I have seen some forums stating that the Express edition was supported. If you can tell for sure what is real, please do not hesitate.
If you are still using VS2005 (and the .Net Framework 2.0), you should use the version 3.1 of the Enterprise library released in May 2007 but expect some features that won’t work.
Other resources
One great resource for is the Hands-On Labs for Enterprise library 4.1 released in March 2009 available from http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=ab3f2168-fea1-4fc2-b40c-7867d99d4b6a. The download weighs a heavy 48.2 MB but it is worthwhile. It contains examples in both VB and C#.
If you want to have a look at a 17 minutes webcast that walks you through installation, setting references, and building your first application using simple validation, Pat Tormey has one available at http://windowsclient.net/learn/video.aspx?v=121945.
This month demo code
The code you can download for this article is in VB only. C# programmers, you can continue to read on as the meat of this article is not in the code but rather in the attributes that decorate the properties.
3 ways of using the Validation Application Block
As you will discover reading this article, the team that as created the VAB (Validation Application Block) made it very flexible and easily extensible. It supports 3 methods of adding validation. I will demo the 3 methods here.
The first method is by using a configuration file. This can be very helpful if your validation rules are simple and also if you want someone like your business analyst to create those rules because the rules can be created using a simple editor. This method is also the only way to add validation when you cannot add them directly into the code (if you have to use a DLL for which you don’t have the code).
The second method is by using attributes on your properties. This is by far the way most developers are creating a great number of validation rules.
The last method should be used only when the attributes are not flexible enough because it requires you to write some code (I know you do that for living). This is very useful when the rules can only be determined by the result of a calculation for example.
In this column, I will spend a little time on the first way (the configuration file) and most of my time mixing the 2 others ways (attributes and code) together.
I will also demonstrate all the features in a Windows Forms application. Near the end of the article, I will also show the VAB can be integrated in a Web Application.
On CodePlex, you will also find an adapter for WPF integration (but I won’t explore it here).
A note worth mentioning
Whichever the validation method you are using, you will never be stopped from setting a property to any value you want (that the data type accepts). What it means is that if you add a rule saying that your string must have between 5 and 20 characters, you will be able to put any number of characters in it. The validation rules are not applied when you set the property. They are using the Get property to inspect the value it currently contains to see if it follows the rules.
It is your responsibility to ensure that all the rules passed before processing the object further more.
The magic recipe
As you will soon discover, using VAB always resumes to the same exact steps.
You first need to add references to some components.
You then need to create the validation rules (via the configuration tool, attributes, and/or code).
Lastly, you need to call the Validate method and check the results.
If that sounds easy, it really is. But the simplicity does not mean that the VAB is useless.
Adding the References
There are always at least 2 DLLs that you need to reference in every project using VAB.
The first one has “Enterprise Library Shared Library” as its component name and is referring to the Microsoft.Practices.EnterpriseLibrary.Common.dll.
The second one has “Enterprise Library Validation Application Block” as its component name and is referring to the Microsoft.Practices.EnterpriseLibrary.Validation.dll.
If you have more than one version of the Enterprise library installed on your computer, be very careful to select the components of version 4.1 as shown in Figure 1.
Figure 1: The minimum references
Later in the article, when we will want to used the integration to a GUI (Windows or Web), we will need to add another reference.
Start writing code
Enough talking, I am sure you are ready to jump into the action. In order to have a more complete demo, I have decided to create a class library component (which we will call BusinessLayer). For the purpose of this demo, it will only contain properties because this is what we want to validate. This very same component from a Windows application and also a Web Application just like it should be in ideal world.
So open Visual Studio 2008 SP1 and create a new class library project. Call it BusinessLayer. In this project add a class named cAddress and paste this code in it:
Public Class cAddress Private mStreet As String Private mCity As String Private mProvince As String Private mPostalCode As String Public Property Street() As String Get Return mStreet End Get Set(ByVal value As String) mStreet = value End Set End Property Public Property City() As String Get Return mCity End Get Set(ByVal value As String) mCity = value End Set End Property Public Property Province() As String Get Return mProvince End Get Set(ByVal value As String) mProvince = value End Set End Property Public Property PostalCode() As String Get Return mPostalCode End Get Set(ByVal value As String) mPostalCode = value End Set End Property End Class
Now add another class to your project, name it cEmployee and paste this code in it:
Public Class cEmployee Private mFirstName As String Private mLastName As String Private mSIN As String Private mDOB As Date Private mEMail As String Private mPhone As String Private mNumberOfFingers As Integer Private mAddress As cAddress Public Property FirstName() As String Get Return mFirstName End Get Set(ByVal value As String) mFirstName = value End Set End Property Public Property LastName() As String Get Return mLastName End Get Set(ByVal value As String) mLastName = value End Set End Property Public Property SIN() As String Get Return mSIN End Get Set(ByVal value As String) mSIN = value End Set End Property Public Property DOB() As Date Get Return mDOB End Get Set(ByVal value As Date) mDOB = value End Set End Property Public Property NumberOfFingers() As Integer Get Return mNumberOfFingers End Get Set(ByVal value As Integer) mNumberOfFingers = value End Set End Property Public Property EMail() As String Get Return mEMail End Get Set(ByVal value As String) mEMail = value End Set End Property Public Property Phone() As String Get Return mPhone End Get Set(ByVal value As String) mPhone = value End Set End Property Public Property Address() As cAddress Get Return mAddress End Get Set(ByVal value As cAddress) mAddress = value End Set End Property End Class
As you can see, there are some properties that are specifically for the purpose of demoing some validation method (like NumberOfFingers). You can also see that the cEmployee class is exposing an Address property that will let us explore validation for an object graph.
Build your class library to ensure that everything is good so far.
Create a Windows Application UI
Add another project to your solution. This time you need to add Windows Forms Application project. Create the GUI so that it looks like the figure 2.
Figure 2: The Windows Forms GUI
All the controls with the white background are plain old textboxes except the DOB (which is a DateTimePicker), Number of Fingers (which is a NumericUpDown), and the big square on the right (which is a Treeview).
You will notice that I have provided default values to the controls because it was a pain to always fill the controls each time I was testing a validator. The SIN (Social Insurance Number) is the Canadian equivalent of the US SSN (Social Security Number).
You also need to add a couple of references to this project. As explained earlier, you should add references to the “Enterprise Library Shared Library” and to the “Enterprise Library Validation Application Block” components. You also need to add a reference to your BusinessLayer component we have created in the previous section.
Create an event handler for the Click event of the button and add this code:
'Create instance and fill it Dim X As New BusinessLayer.cEmployee() With { _ .FirstName = txtFirstName.Text, _ .LastName = txtLastName.Text, _ .SIN = txtSIN.Text, _ .DOB = dtpDOB.Value, _ .NumberOfFingers = Convert.ToInt32(nudFingers.Value), _ .EMail = txtEMail.Text, _ .Phone = txtPhone.Text, _ .Address = New BusinessLayer.cAddress() With { _ .Street = txtStreet.Text, _ .City = txtCity.Text, _ .Province = txtProvince.Text, _ .PostalCode = txtPostalCode.Text}}
Notice that you will need to adjust the name of your controls or this code to be able to compile. With that code, we have an instance of a cEmployee and its cAddress completely filled. This instance is named X.
Now we want to validate this object. Still in the Click event handler, right after the object instantiation, add this code:
'Call the Validate method Dim vr As ValidationResults vr = Validation.Validate(X) 'Display validation results tvwResults.Nodes.Clear() If vr.IsValid Then tvwResults.Nodes.Add("Validation successful!") Else For Each r As ValidationResult In vr Dim node As TreeNode = New TreeNode(r.Message) node.Nodes.Add(String.Format("Key = ""{0}""", r.Key.ToString())) If Not String.IsNullOrEmpty(r.Tag) Then node.Nodes.Add(String.Format("Tag = ""{0}""", r.Tag)) End If node.Nodes.Add(String.Format("Target = ""{0}""", r.Target.ToString())) If r.Validator IsNot Nothing Then node.Nodes.Add(String.Format("Validator = ""{0}""", r.Validator.ToString())) End If tvwResults.Nodes.Add(node) Next tvwResults.ExpandAll() End If
This code call the Validate method from the Validation class (that we got from the add references) passing the object X to validate. This method returns a collection of ValidationResults. If the validation was successful (IsValid), we add a single node to the TreeView control. If the validation fails, we loop through the collection and add each result to the Treeview.
The result contains some properties that are interesting. The Message property returns a description of the error which you will be able to override. The Key property is the name of the property that failed the validation. The Target property is the name of class usually prefixed with the namespace of the property that failed the validation. The Tag property is not used very often (this is why a check if it has a value). It can be used by yourself to help you categorize the results. Finally, the Validator property returns the full name of the validator.
Run the application. And click the Validate button. You shouldn’t be surprised to see that the validation was successful for the simple reason that we haven’t added any rules yet!
Before going to the next step and only if you want to the Configuration editor, add a Application Configuration File (App.Config) file to your project.
Using the Configuration Editor to add rules
We have a class library that has some properties we would like to validate. We also have a GUI ready to validate some rules but we have not defined any rules yet.
One method of providing rules (and I personally don’t like it) is to run an editor that will update the App.Config file. The good thing is that you don’t have to recompile anything in order to have new rules.
While you installed the Enterprise Library, some new menu items should have been added to your Start menu. You should be able to find a new folder titled “Microsoft patterns & practices” containing “Enterprise Library 4.1 – October 2008”. In there, you should be able to find a link titled “Enterprise Library Configuration”. Click on it to start this application.
Click the Open button (from the toolbar of the Enterprise Library Configuration editor) and navigate to your App.Config file we just created. This is the file in which the rules we will create will be persisted. Your configuration will be opened and automatically, a Data Access Application Block will be added to it (and I really don’t know why).
Still in the Configuration editor, right-click your App.Config and select New and then Validation Block.
Right-click the new Validation Application Block entry that was just added and select New and then Type (because we want to validate a type – or a class if you prefer). A Type selector dialog will be displayed. To get your BusinessLayer component displayed, we first need to load it. From the bottom-left of the Type Selector, click the Load from File button and navigate to your BusinessLayer.dll file (surely in a bin\debug folder). Once added, your cEmployee class should be visible (you can use the Filter if you have trouble finding it). Click the cEmployee class and click the Ok button.
It is now the time to create a rule set. There is one thing I haven’t told you yet is that we can have multiple rules on the same properties that are group with the rule set name. When we will call the Validate method, we can specify which rule set to use to validate. I won’t use that feature in this demo but keep it in mind if you come to a point where a single set of rules does not apply to your object at all the time. Even if we don’t use multiple rule set, we need to create one. So right-click the cEmployee type and select New and then Rule Set.
One very important thing, otherwise your rules won’t be used in this demo, go back to the cEmployee type and set the DefaultRule (from the right pane containing properties) to Rule Set which is the name of the rule set we just created.
It is now time to add the properties we would like to validate. Right-click the Rule Set and select New and then Choose Members. A Member Selector dialog will be displayed. Select the FirstName, LastName and Email properties for now and click the OK button.
Right-click the FirstName property, select New and then String Length validator (have you seen all the validators that are available?). In the properties of the validator, set the LowerBound property to 2, the LowerBoundType to Inclusive, and the UpperBound to 20. Do exactly the same for the LastName property. For the Email, property, we will use a regular expression because it makes more sense Right-click the Email property, select New and then Regular Expression Validator. In the properties of the validator, set the pattern to Internet E-Mail address (you gain access to a small listbox when you click the ellipsis button).
Finally, close the Enterprise Library Configuration editor and accept to save the changes. When you go back to Visual Studio, if your App.Config file is open in the editor, you should be asked if you want to reload the App.Config because it was modified outside the source editor. Accept to reload it. Go through the App.Config and you will find/recognize everything we just did.
Run the application. Enter some values in the first name, last name, and E-Mail address fields that you know that will make that validation to fail (or no values at all) and click the Validate button. Do you see errors in the treeview? This configuration tool could be given to a business analyst so that he could add simple validation rules to an application. Another scenario is to add rules to a class library for which you don’t have the source code but this is not very usual.
I won’t spend more time on this as I don’t like this method. I prefer to have my rules closer to my code. The only thing I would like to add about this configuration editor is that, as you would expect, reopen the same configuration file and add or modify existing rules.
You should now delete the App.Config from your project to stop those rules from interfering with the new rules we will create.
Adding validation rules using attributes
This is my preferred method, at least for simple rules like the one we processed using the editor in the previous section.
Because you add the attributes directly on the properties, you will understand that you will need to have the source code of the classes containing those properties (I hope that it is not a problem).
Go back to the BusinessLayer project and open the cEmployee class. We will start adding validation to the properties of that class. I will explain some details about those validators at the same time.
An attributes is added like this:
<StringLengthValidator(2, 20)> _ Public Property FirstName() As String Get Return mFirstName End Get Set(ByVal value As String) mFirstName = value End Set End Property
When you look at the signature of validators, you will find optional parameters that exist for most of them. The parameters will vary from one validator to another. For example, in the Regular Expression validator, expect to see a pattern parameter.
There is a Tag parameter to help you categorize your results. This is a string in which you can put any value to help you. Do you remember when we filled the treeview with the validation results? We have added this parameter and I told you at this time that it was almost always empty.
Another common parameter is Ruleset which is also a string. When I introduced you the configuration editor, we had to create a ruleset, this is exactly the same property here.
One common and very useful parameter is the MessageTemplate in which you can store the message that will be made available to the validation results. This string can also contains placeholder to include some variables. You can also use the Resource file to stock your messages which will make sense when you need to support localized versions of your application. You can achieve this by setting MessageTemplateResourceName and MessageTemplateResourceType parameters.
Another common parameter is called Negated. This is a Boolean value. It should be pretty obvious how and when to use (just think of any condition in front of which you add the Not keyword).
The StringLengthValidator
The first validator that we will use is to validate the length of a string. So to the FirstName and LastName properties, add this attributes:
<StringLengthValidator(2, 20)> _
This validator is really simple. All it does is to ensure that the string contains somewhere between 2 and 20 characters. The 2 and 20 are known as the lower and upper bounds.
I know you cannot wait any longer. Run the application and see if it is working. Don’t worry, I will wait for you!
The ContainsCharactersValidator and the ValidatorComposition
Go back to the FirstName property and replace the attribute with this combination:
<ValidatorComposition(CompositionType.And), _ StringLengthValidator(3, 20), _ ContainsCharactersValidator("ric", ContainsCharacters.All)> _
This is an example where multiple attributes/rules are applied to a single property. This specific example validates that the length of the string has 3 to 20 characters and it also validates that the string contains at least the characters R, I, and C. The characters don’t have to be contiguous nor in that order. They only have to be contained in the string.
On the first line, you can see the ValidatorComposition attribute. In this case, it is not strictly required because the composition is a CompositionType.And and this is the default value which is implicit if you don’t specify it. You could also set the composition to CompositionType.Or.
The RegexValidator
Another very useful validator when it comes to validate values to see if they match a pattern is the Regular Expression validator.
Simply pass your regular expression string into the Pattern parameter and you are done.
For example, this would be the attribute to add in front of the Email property (also noticed that I have provided a message template because the message provided by the library is horrible for users):
<RegexValidator("\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*", MessageTemplate:="Invalid e-mail address")> _
Another example of a property validated using a regular expression could be the Phone. This would be this attribute:
<RegexValidator("((\(\d{3}\) ?)|(\d{3}[- \.]))?\d{3}[- \.]\d{4}(\s(x\d+)?){0,1}$")> _
The RangeValidator
Sometimes you want to validate the value entered falls into a specific range. This is exactly what the RangeValidator is for.
For example, the NumberOfFingers property could have this attribute that would validate that the employee as 0 to 10 fingers:
<RangeValidator(0, RangeBoundaryType.Inclusive, 10, RangeBoundaryType.Inclusive)> _
The RelativeDateTimeValidator
We often have to compare a date property to the current date to ensure that people are old enough (for example).
This is easily done using the RelativeDateTimeValidator. In our class, we have the DOB property. I have added this validator which ensures that the employee is aged between 6 and 66 years old (do you see the -66 in the lowerBound property and the -6 in the upperBound property?).
<RelativeDateTimeValidator(-66, DateTimeUnit.Year, -6, DateTimeUnit.Year, MessageTemplate:="Must be between 6 and 66 years old.")> _
Adding validation to the cAddress class
The main purpose of the cAddress class is mainly to show you a particularity when you have an object graph.
So to make it simple, add this StringLengthValidator to the Street and City properties (this will let you keep the field empty but will trigger a validation error if you have more than 20 characters):
<StringLengthValidator(0, 20)> _
The PostalCode property is another easy one to set because we already talked about the RegexValidator (and Canadian postal code at the minimum should fit a pattern A9A 9A9). So this is the attribute you could have:
<RegexValidator("^[a-zA-Z]{1}[0-9]{1}[a-zA-Z]{1}(\-| |){1}[0-9]{1}[a-zA-Z]{1}[0-9]{1}$")> _
The DomainValidator
This is another validator useful when you want to compare your value against a list of limited known values. For example, my cAddress class will return a validation error if the province value is not in the list of (QC, ON, NB) using this attribute (it also validates that the length is exactly 2):
<StringLengthValidator(2, 2), _ DomainValidator("QC", "ON", "NB")> _
Another run
You should now run the application once again and ensure that all the rules are triggered.
Do you see something not working as expected? Return to the running application and try to find validation errors that are not reported.
If you found that no validation are reported from the cAddress class, you are a genius (otherwise you failed in copy-paste).
The reason is simple. In the cEmployee class, there are no attributes on the Address property. So by default, this property (and all the properties of the cAddress class are not validated). Luckily there is a simple attribute that will fix this problem. By adding this attribute to the Address property of the cEmployee class will fix all problems:
<ObjectValidator()> _
Validating the Social Security number or how to validate using code
So far, we added a lot of very useful attributes that are doing a lot of usual validations. But what if your validation is the result of a calculation or a check into a database? The attributes won’t let you go that far but that doesn’t mean that the VAB is not able to do it!
In my cEmployee class, I have the SIN property (which is the only one that has no validation rule yet). The last digit of a Canadian Social Insurance Number (SIN) is a check digit. To be able to validate the check digit, I have written this method. This method has to be a Sub (or Void for C# guys) and accept a ValidationResults parameter.
Public Sub ValidateSIN(ByVal vr As ValidationResults) Dim strSIN As String = Me.SIN.Trim.Replace(" "c, "") Dim intLen As Integer = strSIN.Length Dim intTotal As Integer Dim intValue As Integer If intLen = 9 Then For intI As Integer = 0 To intLen - 2 intValue = (((intI) Mod 2) + 1) * Integer.Parse(strSIN.Substring(intI, 1)) If intValue > 9 Then intValue = (intValue Mod 10) + 1 End If intTotal += intValue Next If (intTotal + Integer.Parse(strSIN.Substring(intLen - 1, 1))) Mod 10 <> 0 Then vr.AddResult(New ValidationResult("The SIN is invalid", Me, "SIN", Nothing, Nothing)) End If Else vr.AddResult(New ValidationResult("SIN length is invalid", Me, "SIN", Nothing, Nothing)) End If End Sub
The core of this method is the calculation for the check digit. When you detect invalid values, you can add validation error yourself to the collection of ValidationResults received in parameters. This is exactly what this line is doing (note that the 2 Nothing values at the end are simply values for the Tag property and the Validator name which are not used in this case):
vr.AddResult(New ValidationResult("The SIN is invalid", Me, "SIN", Nothing, Nothing))
Even after you have added this method, the validation of the SIN won’t be done magically. You need to add 2 new attributes.
The first new attribute is added to the ValidateSIN method and is the following:
<SelfValidation()> _
The second attribute has to be added to class to let the validator engine knows that there are more than just properties to check. This attribute that you need to add to the class is this one:
<HasSelfValidation()> _
Now, if you rerun the application, the ValidateSIN method will be called each time the Validate but will be clicked on the form (it would be more exact to say every time the Validation.Validate method will be called).
Creating a Validation component
Even if we achieve the goal of adding validation rules through code, this method is far from the best practices of reusability.
If you are building your own classes at the same time you are reading this, I will ask to now comment out the ValidateSIN method and also the HasSelfValidation attribute on the class.
What we will do here is to create a new class library that will contain our validation code.
The first thing you need to do is to create another Class Library project to your solution (I named mine CustomValidators). You need to add a reference to the “Enterprise Library Validation Application Block” (Microsoft.Practices.EnterpriseLibrary.Validation.dll). In this new project add a new class (or rename the current Class1) and name it SinValidator.
Inherits this class from the Validator class and specify the (Of String) type like this:
Public Class SINValidator Inherits Validator(Of String)
Because you inherit this Validator class, you must create a constructor that will receive the value to validate in parameter that you will send to your base (don’t even need to stock it):
Public Sub New(ByVal pSin As String) MyBase.New(String.Empty, pSin) End Sub
You also need to override the DefaultMessageTemplate property but most of the time we throw an exception because it we will provide the error message at the time will detect the error:
Protected Overrides ReadOnly Property DefaultMessageTemplate() As String Get Throw New NotImplementedException End Get End Property
The last method you need to overwrite is the DoValidate method in which you basically post the code we had in our previous method.
Protected Overloads Overrides Sub DoValidate(ByVal objectToValidate As String, _ ByVal currentTarget As Object, _ ByVal key As String, _ ByVal validationResults As ValidationResults) Dim strSIN As String = objectToValidate.Trim.Replace(" "c, "") Dim intLen As Integer = strSIN.Length Dim intTotal As Integer Dim intValue As Integer If intLen = 9 Then For intI As Integer = 0 To intLen - 2 intValue = (((intI) Mod 2) + 1) * Integer.Parse(strSIN.Substring(intI, 1)) If intValue > 9 Then intValue = (intValue Mod 10) + 1 End If intTotal += intValue Next If (intTotal + Integer.Parse(strSIN.Substring(intLen - 1, 1))) Mod 10 <> 0 Then LogValidationResult(validationResults, "The SIN is invalid", currentTarget, key) End If Else LogValidationResult(validationResults, "SIN length is invalid", currentTarget, key) End If End Sub
This is the same code except that instead of reading the SIN property (which is not available here), we have to use the objectToValidate parameter. And also, instead of using the AddResult method to log a broken rule, we need to use the LogValidationResult method.
To make this validation class even more useful, we will add just a couple of more lines of code.
I usually create right at the top of the class we just created (SINValidator). The code is as follows:
Public Class SINValidatorAttribute Inherits ValidatorAttribute Protected Overloads Overrides Function DoCreateValidator(ByVal targetType As System.Type) As Validator Return New SINValidator(Me.Tag) End Function End Class
So this code is creating a new class (SINValidatorAttribute) that inherits the ValidatorAttribute class. The only thing we need to add to this class is an override to the DoCreateValidator that returns a new instance of our validator we just created.
The magic thing that will happen because we have created this small class is that our validator will be made available as an attribute just like all the others we have used so far.
Isn’t it wonderful?
It is now time to build your solution.
Use your new custom validator
Go back to your BusinessLayer class library and add a reference to your new CustomValidators component.
Open the cEmployee class, add this Imports statement (or using in C#) at the top of the class:
Imports CustomValidators
Now localize the SIN property in the class and add this attribute to it:
<SINValidator()> _
You can now try your application. It should just work as expected but you now a reusable validator that looks just like any other one.
Using the Windows Forms integration
Have you ever used the ErrorProvider component? A very long time ago (almost in another era!), I have written an article on that topic which is still available from The ErrorProvider Control (in Windows Forms).
The reason why I ask you the question is that the VAB integrates well the ErrorProvider. This is how we can achieve this.
First, you need to add an ErrorProvider component to the form.
You also need to add a component to your form that is probably not in your toolbox yet. Right-click the toolbox and select the Choose items menu item. In the list,find the ValidationProvider 4.1 check the checkbox and click the OK button. Now you can add an instance of the ValidationProvider to your form. In fact you would need one instance for each class to validate – like cEmployee and cAddress in my case. The downloaded demo integrates the 2 classes.
In the properties of the ValidationProvider, you need to bind it to the ErrorProvider component that you also placed on the form by setting the ErrorProvider property to ErrorProvider1 (or to the name you gave it).
You also need to set the SourceTypeName property of the Validation provider to the class to validate (this is why you need one instance for each class to validate). In my case, the class in named cEmployee and is part of the BusinessLayer namespace so we need to provide “BusinessLayer.cEmployee, BusinessLayer” as the SourceTypeName.
Now we can go on each control we want to bind to the ErrorProvider and set a couple of properties. So select the first name textbox, set the “PerformValidation on ValidationProvider1” to True and the “SourcePropertyName on ValidationProvider1” to the name of the property in the class which is FirstName.
Do the same for your other properties that belongs to the cEmployee class.
Run the application. Empty the first name textbox and try to click the Validate button or to tab elsewhere. You should not be able. Sure you will get the blinking icon telling you that you have an error and you can hover your mouse pointer over it to see the message in tooltip but this is a really bad behaviour that your users won’t like for sure.
Once again, the solution to this problem is simple. There is a property on the form itself named AutoValidate. Change its value to EnableAllowFocusChange and you will be able to another control even though you have an error.
Figure 3: The Windows Forms GUI in action
Using the ASP.Net Web application integration
This article wouldn’t be complete if I wouldn’t prove that the VAB can also integrate easily with ASP.Net web applications.
To the same solution you are working since the beginning, add a new ASP.Net Web application.
Add a reference to your BusinessLayer component.
Just like we did for the Windows forms integration, we need to add a new control to the toolbox. Right-click the toolbox and select the choose items menu item. Select PropertyProxyValidator 4.1 from the list and click the OK button.
Create a simple GUI with a couple of textbox. Next to each control you want to validate, add a PropertyProxyValidator. In the property of the validator, set the ControlToValidate property accordingly, set the PropertyName to the name of the property in the class, and lastly set the SourceTypeName to “BusinessLayer.cEmployee, BusinessLayer” like we did for Windows controls. The full code for a single control would then look like this:
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox> <cc1:PropertyProxyValidator ID="PropertyProxyValidator1" runat="server" ControlToValidate="TextBox1" PropertyName="FirstName" SourceTypeName="BusinessLayer.cEmployee, BusinessLayer"> </cc1:PropertyProxyValidator>
Also add a button to your web form and in the click event of this button, add this code:
If IsValid Then Label1.Text = "Valid" Else Label1.Text = "NOT Valid" End If
In my case (download the full demo to see it), I have added a label where I simply write if the validation was successful or not.
Figure 4: The web GUI in action
View your page in the browser and click the button. You will find out that without anything else to do, you have the red messages that will automatically appear when rules are broken.
Conclusion
This is my longest article so far (and surely one of the longest ever) but I think it seriously worth it.
That’s too easy to implement to ignore it. The next time you need to validate data, give a try to those attributes.
This application block is simply brilliant, simple, flexible, and extensible. I really encourage you to give it a serious try. You won’t regret it.