asp tutorials, asp.net tutorials, sample code, and Microsoft news from 15Seconds
Data Access  |   Troubleshooting  |   Security  |   Performance  |   ADSI  |   Upload  |   Email  |   Control Building  |   Component Building  |   Forms  |   XML  |   Web Services  |   ASP.NET  |   .NET Features  |   .NET 2.0  |   App Development  |   App Architecture  |   IIS  |   Wireless
 
Pioneering Active Server
 Power Search








Active News
15 Seconds Weekly Newsletter
• Complete Coverage
• Site Updates
• Upcoming Features

More Free Newsletters
Reference
News
Articles
Archive
Writers
Code Samples
Components
Tools
FAQ
Feedback
Books
Links
DL Archives
Community
Messageboard
List Servers
Mailing List
WebHosts
Consultants
Tech Jobs
15 Seconds
Home
Site Map
Press
Legal
Privacy Policy
internet.commerce














internet.com
IT
Developer
Internet News
Small Business
Personal Technology
International

Search internet.com
Advertise
Corporate Info
Newsletters
Tech Jobs
E-mail Offers

HardwareCentral
Compare products, prices, and stores at Hardware Central!

Populating ASP.NET Form Validators from XML
By Robert Walling
Rating: 3.9 out of 5
Rate this article


  • email this article to a colleague
  • suggest an article

  • download source code
  • ASP.NET form validators spelled the end of repetitive validation code. What used to take hours can now be accomplished in a matter of minutes using Visual Studio.NET's drag-and-drop interface. ASP.NET form validators offer flexibility both in the types of validation they support and in displaying error messages to users. Most developers shudder at the thought of returning to the validation techniques of three years ago.

    Within the beauty of form validators lurks a hidden beast that only awakens in large web applications. In a 10 page data-entry application, hard-coding error messages and regular expressions into the validators is a fast and easy way to develop. You'll likely wind up with 2 or 3 "First Name" textboxes, each having a "First Name" required field validator and regular expression validator, each with their own hard-coded error message. Though not an ideal situation, it is certainly manageable. As the page count increases, however, maintaining these strings becomes a headache, especially if the product development department is choosy about error message syntax. When they ask to change "First Name is a required field" to "Please enter a first name" how many lines of code are touched?

    The Solution

    The requirements for the solution are as follows:

    1. The solution must provide common storage for multiple values based on a key. In our example above, "FirstName" would be the key and the values stored would be RequiredErrorMessage, RegularExpressionErrorMessage, and RegularExpression.
    2. The solution must be fast. These values will be accessed on the first page load of nearly every page in the web application, so they must be held in a screaming fast storage mechanism.
    3. The solution must be easily editable. Developers should be able to view and edit any value with minimal effort.

    The solution, as demonstrated in the downloadable code sample, consists of the following:

    1. An XML file used to store the keys and values.
    2. A singleton class that stores the XML data in memory. If you are unfamiliar with the singleton design pattern see the section below titled "A Brief Introduction to Design Patterns."
    3. A method named BindErrorChecking() that appears on every page containing a validator or textbox. The first time a page loads a call is made to BindErrorChecking(), which retrieves the values from the singleton and assigns them to the appropriate validator or textbox. The following syntax is used:

    revFirstName.ValidationExpression = Validation.Field("FirstName").RegEx

    The XML File

    We'll begin by examining a snippet of the XML file, Validation.xml:

    <?xml version="1.0" encoding="utf-8" ?>
    <Validations>
      <Field>
        <Name>FirstName</Name>
        <RegEx>^[a-zA-Z]{0,50}$</RegEx>
        <MaxLength>50</MaxLength>
        <RegExErrorMessage>Invalid first name.</RegExErrorMessage>
        <RequiredErrorMessage>Please enter a first name.</RequiredErrorMessage>
      </Field>
      <Field>
        <Name>LastName</Name>
        <RegEx>^[a-zA-Z']{0,50}$</RegEx>
        <MaxLength>50</MaxLength>
        <RegExErrorMessage>Invalid last name.</RegExErrorMessage>
        <RequiredErrorMessage>Please enter a last name.</RequiredErrorMessage>
      </Field>
    ...
    
    • <Name> is the key used in the calling code to retrieve the appropriate values.
    • <RegEx> is the regular expression that would be assigned to the ValidationExpression property of a RegularExpressionValidator.
    • <MaxLength> is another property that is typically hard-coded and duplicated throughout code. It corresponds to the MaxLength property of a textbox.
    • <RegExErrorMessage> is the error message to display if the regular expression validation fails.
    • <RequiredErrorMessage> is the error message to display if the required field validation fails.

    This file will be modified throughout development as new form fields are added. It is very helpful to keep the elements ordered alphabetically by their <Name>.

    A Brief Introduction to Design Patterns

    If you are familiar with design patterns feel free to skip down to the Singleton section, below.

    After many years of using software to solve business problems, computer scientists began to notice that they faced a similar set of repeated problems from one application to the next. In 1995 the book Design Patterns: Elements of Reusable Object-Oriented Software coined the term "Design Patterns" to describe standard solutions to common problems in software design. There are now dozens of books written on the subject, many of which provide language-specific examples. Microsoft has a section of their site dedicated to .NET Design Patterns: http://www.microsoft.com/patterns/.

    One of the most often-used design patterns is the Singleton. The Singleton pattern ensures that only one instance of a class can be instantiated. Any calling code that uses an instance of a Singleton accesses the same portion of memory. The benefits of this pattern are obvious in the current scenario, where having a copy of the Validation.xml file in memory for each user on the site is unnecessary and would adversely affect scalability.

    With this in mind, let's examine the Validation class, which implements the Singleton design pattern.

    The Validation Class

    The following are the first few lines from the Validation class, defined in Validation.vb:

    Public NotInheritable Class Validation
    
      Private Shared _instance As Validation = New Validation
      Public Shared ReadOnly Property instance() As Validation
        Get
          Return _instance
        End Get
      End Property
    

    First notice that the class is NotInheritable, meaning it cannot be extended through inheritance. This class was not designed to be a base class and inheriting from it would not make much sense from an object oriented perspective.

    The core of a singleton is its ability to maintain a single instance of itself no matter how many users instantiate it. This is possible because instantiation of the object is controlled by the object itself. This is achieved by making its constructor private, which ensures that calling code cannot "accidentally" instantiate the Validation class. When separate instances of calling code retrieve values from this class, they all indirectly use the shared _instance variable.

      Public Class ValidationField
        Public Name As String = String.Empty
        Public RegEx As String = String.Empty
        Public MaxLength As Integer = 0
        Public RegExErrorMessage As String = String.Empty
        Public RequiredErrorMessage As String = String.Empty
      End Class
    
      Private _cachedValidationFields As New Collections.Specialized.HybridDictionary
    
      Public Shared ReadOnly Property Field(ByVal fieldName As String) As ValidationField
        Get
          Return CType(instance._cachedValidationFields(fieldName), ValidationField)
        End Get
      End Property
    

    The code continues by declaring a nested class named ValidationField that serves as a data container for a single Validation.xml <Field> tag.

    The Private HybridDictionary _cachedValidationFields, populated in Validation's constructor (see below), is the core of this class, as it holds the collection of ValidationField objects. _cachedValidationFields can only be accessed through the Field property, which retrieves a particular ValidationField object from the collection based on a string key.

    When calling code accesses a specific field using the syntax Validation.Field("FirstName").MaxLength, the shared peroperty named instance is used to retrieve the appropriate value.

    The next section of code is the constructor:

      '**************************************************************
      ' New 
      ' Parses the Validation.xml file
      '**************************************************************
      Private Sub New()
    
        Dim ds As New DataSet
        ds.ReadXml(Current.Server.MapPath("Validation.xml"))
    
        Dim dr As DataRow
        For Each dr In ds.Tables(0).Rows
    
          Dim Field As New ValidationField
    
          Field.Name = CStr(dr.Item("Name"))
          Field.RegEx = CStr(dr.Item("RegEx"))
          Field.MaxLength = CInt(dr.Item("MaxLength"))
          Field.RegExErrorMessage = CStr(dr.Item("RegExErrorMessage"))
          Field.RequiredErrorMessage = CStr(dr.Item("RequiredErrorMessage"))
    
          _cachedValidationFields.Add(Field.Name, Field)
        Next
    
      End Sub
    

    Begin by noting that the constructor is Private, the hallmark of a singleton. This constructor is only called once, the first time this class is instantiated. Every time an instance of this object is called after the first time, the "in memory" copy contained in _instance is used. In the accompanying test application this first access happens as soon as ValidationTest.aspx retrieves a value from the Validation class. A line could be added to the Application_Start method in Global.asax to ensure the values are read on application start-up.

    The constructor performs the basics discussed earlier:

    1. It reads Validation.xml into memory, in this case a DataSet.
    2. It reads through each row of the DataSet and populates a new ValidationField object.
    3. Finally, it adds the ValidationField object to the _cachedValidationFields collection.

    Once the DataSet is populated it is not changed until it is reloaded from the XML when the application is restarted, either by modifying the Web.config or recycling the aspnet worker process.

    The last two bits of code are two "bonus" subroutines not used in this sample project, but included for use in larger applications:

      Public Shared Sub Reset()
        _instance = New Validation
      End Sub
    

    The Reset method allows for dynamic reloading of Validation.xml during runtime. A web page could very easily call this method in a button event handler to allow administrators to reload Validation.xml on the fly without restarting the application.

    Public Shared Sub AssertValidArgument(ByVal ToValidate As String,
      ByVal FieldName As String)
    
      If Not RegularExpressions.Regex.IsMatch(ToValidate,
        Validation.Field(FieldName).RegEx) Then
    
        Throw New Exception(Validation.Field(FieldName).RegExErrorMessage)
    
      End If
    End Sub
    

    AssertValidArgument is designed to be called from the business tier to ensure the same validation that's performed in the UI is performed in the business tier.

    Accessing Validation Fields in an ASP.NET Page

    Accessing the values contained in the Validation object is trivial, and can be seen in the code-behind of ValidationTest.aspx in BindErrorChecking(), a method that is called on the first page load:

      Protected Sub BindErrorChecking()
    
        ' Set textbox maxlengths
        txtFirstName.MaxLength = Validation.Field("FirstName").MaxLength
        ...
    
        ' Set regular expressions
        revFirstName.ValidationExpression = Validation.Field("FirstName").RegEx
        ...
        
        ' Set regular expression error messages
        revFirstName.ErrorMessage = Validation.Field("FirstName").RegExErrorMessage
        ...
    
        ' Set required field error messages
        rfvFirstName.ErrorMessage = Validation.Field("FirstName").RequiredErrorMessage
        ...
    
      End Sub
    

    Pros and Cons of this Solution

    The main advantage of this approach is the maintainability provided by storing the myriad of string values in a single repository. In addition, using XML means only a text editor is required to modify these values, eliminating the need for recompilation. Finally, this approach allows the web and business tier to easily share the same regular expressions and error messages.

    One disadvantage of this approach is that the ViewState is slightly larger than when hard-coding the values into the validators. When the values are hard-coded they are compiled into the dll, but when they are set dynamically at runtime they must be passed in the ViewState. For intranet or broadband users this is not an issue but for dial-up connections this could contribute to increased page load times.

    Further Work

    One opportunity to extend this class would be to add the capability to handle range validators, compare validators, and custom validators.

    Conclusion

    Large applications come with many challenges that, given the wrong approach, can turn into maintenance nightmares. As applications grow they tend to contain large quantities of repetitive information. The Validation class offers an easy to maintain, XML-based solution to an otherwise difficult problem.

    A special thanks to Chris Mullins of Winfessor (www.winfessor.com) for providing the idea this article is based on. Thanks a lot!

    About The Author

    Rob Walling is a Microsoft Certified Application Developer with five years of development experience. His areas of expertise include ASP.NET, VB.NET, and web application architecture. His technical articles have been published on various websites. You can reach him at rwalling *=* thenumagroup.com (substitue '@' for '*=*').

  • Rate This Article
    Not HelpfulMost Helpful
    1 2 3 4 5
    Supporting Products/Tools
    Stonebroom.ASP2XML
    Stonebroom.ASP2XML(c) is an interface component designed to make building applications that transport data in XML format much easier. It can be used to automatically pass updates back to the original data source.
    [Top]
    Other Articles
    Sep 22, 2005 - Implementing Remote Calling Without Using AJAX
    Right now the latest buzzword around town is AJAX. AJAX is an acronym for Asynchronous JavaScript and XML and is a method used to implement remote calling. The problem is that AJAX is only implemented in ASP.NET 2.0. This article will show you one way to implement remote calling without using AJAX or the XMLHttpRequest object. The technique outlined can even be used from classic ASP and is sufficient for most remote calling needs.
    [Read This Article]  [Top]
    Aug 18, 2005 - SQL Server 2005 XQuery and XML-DML - Part 3
    This article is the third and final installment of Alex Homer's series covering the new XML support in Microsoft SQL Server 2005. In it he covers updating the contents of xml columns, comparing traditional XML update techniques with XQuery, and using XQuery in a managed code stored procedure.
    [Read This Article]  [Top]
    Aug 11, 2005 - SQL Server 2005 XQuery and XML-DML - Part 2
    In the second part of his series on SQL Server 2005's new XML support, Alex Homer looks at extracting data from XML columns, comparing traditional XML data access approaches with XQuery, and combining XQuery and XSL-T.
    [Read This Article]  [Top]
    Aug 3, 2005 - SQL Server 2005 XQuery and XML-DML - Part 1
    Microsoft SQL Server 2005 now offers great support for and close integration with XML as a data persistence format. In the first article of his series examining this new support, Alex Homer offers an overview of how SQL Server 2005 stores XML documents and schemas, examines how it supports querying and manipulating XML documents, and provides a simple test application that allows you to experiment with XQuery.
    [Read This Article]  [Top]
    Jun 30, 2005 - Reading and Writing XML in .NET Version 2.0 - Part 3, Cont'd
    In the final article of his series on reading and writing XML in .NET 2.0, Alex Homer looks at how the updated XML document store objects XmlDocument, XmlDataDocument and PathDocument can be used to read, persist and write XML documents and fragments more easily and more efficiently than in .NET 1.x.
    [Read This Article]  [Top]
    Jun 29, 2005 - Reading and Writing XML in .NET Version 2.0 - Part 3
    In the final article of his series on reading and writing XML in .NET 2.0, Alex Homer looks at how the updated XML document store objects XmlDocument, XmlDataDocument and PathDocument can be used to read, persist and write XML documents and fragments more easily and more efficiently than in .NET 1.x.
    [Read This Article]  [Top]
    Jun 16, 2005 - Reading and Writing XML in .NET Version 2.0 - Part 2, Cont'd
    Alex Homer continues his series on reading and writing XML in .NET 2.0. In part one, we focused on the reading side of things, examining the XmlReader and XmlReaderSettings classes. In this article, we move on to look at the XmlWriter and XmlWriterSettings classes, and how they can be used to write XML documents and fragments more easily and more efficiently than in version 1.x of .NET.
    [Read This Article]  [Top]
    Jun 15, 2005 - Reading and Writing XML in .NET Version 2.0 - Part 2
    Alex Homer continues his series on reading and writing XML in .NET 2.0. In part one, we focused on the reading side of things, examining the XmlReader and XmlReaderSettings classes. In this article, we move on to look at the XmlWriter and XmlWriterSettings classes, and how they can be used to write XML documents and fragments more easily and more efficiently than in version 1.x of .NET.
    [Read This Article]  [Top]
    Jun 2, 2005 - Reading and Writing XML in .NET Version 2.0 - Part 1, Cont'd
    In the first part of his series on reading and writing XML in .NET 2.0, Alex Homer discusses the XmlReader and XmlReaderSettings classes. The XmlReader exposes several useful new features and the all new XmlReaderSettings class makes it easy to generate single or multiple instances of an XmlReader with a range of useful properties.
    [Read This Article]  [Top]
    Jun 1, 2005 - Reading and Writing XML in .NET Version 2.0 - Part 1
    In the first part of his series on reading and writing XML in .NET 2.0, Alex Homer discusses the XmlReader and XmlReaderSettings classes. The XmlReader exposes several useful new features and the all new XmlReaderSettings class makes it easy to generate single or multiple instances of an XmlReader with a range of useful properties.
    [Read This Article]  [Top]
    Mailing List
    Want to receive email when the next article is published? Just Click Here to sign up.

    Support the Active Server Industry



    JupiterOnlineMedia

    internet.comearthweb.comDevx.commediabistro.comGraphics.com

    Search:

    Jupitermedia Corporation has two divisions: Jupiterimages and JupiterOnlineMedia

    Jupitermedia Corporate Info


    Legal Notices, Licensing, Reprints, & Permissions, Privacy Policy.

    Advertise | Newsletters | Tech Jobs | Shopping | E-mail Offers

    Solutions
    Whitepapers and eBooks
    Microsoft Article: Will Hyper-V Make VMware This Decade's Netscape?
    Microsoft Article: 7.0, Microsoft's Lucky Version?
    Microsoft Article: Hyper-V--The Killer Feature in Windows Server 2008
    Avaya Article: How to Feed Data into the Avaya Event Processor
    Microsoft Article: Install What You Need with Windows Server 2008
    HP eBook: Putting the Green into IT
    Whitepaper: HP Integrated Citrix XenServer for HP ProLiant Servers
    Intel Go Parallel Portal: Interview with C++ Guru Herb Sutter, Part 1
    Intel Go Parallel Portal: Interview with C++ Guru Herb Sutter, Part 2--The Future of Concurrency
    Avaya Article: Setting Up a SIP A/S Development Environment
    IBM Article: How Cool Is Your Data Center?
    Microsoft Article: Managing Virtual Machines with Microsoft System Center
    HP eBook: Storage Networking , Part 1
    Microsoft Article: Solving Data Center Complexity with Microsoft System Center Configuration Manager 2007
    MORE WHITEPAPERS, EBOOKS, AND ARTICLES
    Webcasts
    Intel Video: Are Multi-core Processors Here to Stay?
    On-Demand Webcast: Five Virtualization Trends to Watch
    HP Video: Page Cost Calculator
    Intel Video: APIs for Parallel Programming
    HP Webcast: Storage Is Changing Fast - Be Ready or Be Left Behind
    Microsoft Silverlight Video: Creating Fading Controls with Expression Design and Expression Blend 2
    MORE WEBCASTS, PODCASTS, AND VIDEOS
    Downloads and eKits
    Sun Download: Solaris 8 Migration Assistant
    Sybase Download: SQL Anywhere Developer Edition
    Red Gate Download: SQL Backup Pro and free DBA Best Practices eBook
    Red Gate Download: SQL Compare Pro 6
    Iron Speed Designer Application Generator
    MORE DOWNLOADS, EKITS, AND FREE TRIALS
    Tutorials and Demos
    How-to-Article: Preparing for Hyper-Threading Technology and Dual Core Technology
    eTouch PDF: Conquering the Tyranny of E-Mail and Word Processors
    IBM Article: Collaborating in the High-Performance Workplace
    HP Demo: StorageWorks EVA4400
    Intel Featured Algorhythm: Intel Threading Building Blocks--The Pipeline Class
    Microsoft How-to Article: Get Going with Silverlight and Windows Live
    MORE TUTORIALS, DEMOS AND STEP-BY-STEP GUIDES