Solved

Form validation in asp .net 2. How do I create a reusable structure for validating basic form input?

Posted on 2008-09-30
9
472 Views
Last Modified: 2013-11-07
Okay, in my company we are converting a lot of ASP application to ASP .NET and C#. There is a convention that is used on form fields in the ASP pages. If a field is required, the field name is prefixed with an r. I was asked to adopt this methodology to .Net. So I have created a class that will perform validation on a given form. The methodology I adapted was to suffix my field names with an underscore and then list any subscripts necessary for validation.

So far the possible subscripts I have come up with are:
r - required
d - date
e - email
n - numeric

An example would be txtFirstName_r, for a text box control that is a required field. The subscripts can also be combined in any order that makes sense (i.e. you wouldn't want a field to have both a _d and n as that is contradictory) so you could have txtDateEntered_rd.

There is the obvious draw back of having only a maximum of 26 subscripts in addition to the fact that if I went sequentially through the alphabet, the subscript would have no intuitive correlation to its purpose.

Mind you this is only intended for simple and basic validations. Actual business validations would be accomplished through another means.

I will post the code I have for this shortly.

What I would like is a critique of this course of action. It seems like its pulling teeth whenever I go to find a method of validating my form that can be reused fairly easily with minimal changes.

As for the validation controls that come with .Net, they seem a crock and a gimmick and I would be surprised if they were ever used in any enterprise class sort of project. The amount of things that have to be redone on a page to page basis seems amazing. Furthermore, you get to do it all over again for the next project. If any one has issue with this, I would love to be corrected as my concern is far more than about simply being right. I just want a method of validating form input that is fairly simplistic and easily reusable.

Thanks for your time. I'll post my code within the hour.
0
Comment
Question by:baijajusav
  • 5
  • 2
9 Comments
 
LVL 3

Author Comment

by:baijajusav
ID: 22606166
Unfortunately, it seems I cannot upload a zip of the entire site. I guess I will list everything here file by file. Everything is documented in enough detail I would say. I'm hoping you won't have much trouble following the code. One thing to announce real quick is that I needed a way to associate a meaningful name for each control to be used in validation messages pertaining to a given control...so instead of a validation message saying txtRequired_r is required, it would say Required is required, where Required would be the name of the aforementioned text box.

If you create a new basic asp .net application, you should be able to copy and paste the code directly.

///////////////////////////////////////////////////////////DEFAULT.ASPX
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
        <div>
             <table>
                  <tr>
                       <td style="width: 100px">
                       </td>
                       <td style="width: 100px">
                       </td>
                       <td style="width: 100px">
                       </td>
                  </tr>
                  <tr>
                       <td style="width: 100px; height: 21px">
                            Required</td>
                       <td style="width: 100px; height: 21px">
                       </td>
                       <td style="width: 100px; height: 21px">
                            <asp:TextBox ID="txtRequired_r" runat="server"></asp:TextBox></td>
                  </tr>
                  <tr>
                       <td style="width: 100px">
                       </td>
                       <td style="width: 100px">
                       </td>
                       <td style="width: 100px">
                            <asp:TextBox  ID="TextBox2" runat="server"></asp:TextBox></td>
                  </tr>
                  <tr>
                       <td style="width: 100px; height: 26px">
                            Length:</td>
                       <td style="width: 100px; height: 26px">
                       </td>
                       <td style="width: 100px; height: 26px">
                            <asp:TextBox ID="txtLength_rl" runat="server"></asp:TextBox></td>
                  </tr>
                  <tr>
                       <td style="width: 100px; height: 26px">
                            Email:</td>
                       <td style="width: 100px; height: 26px">
                       </td>
                       <td style="width: 100px; height: 26px">
                            <asp:TextBox ID="txtEmail_re" runat="server"></asp:TextBox></td>
                  </tr>
                  <tr>
                       <td style="width: 100px">
                            Number:</td>
                       <td style="width: 100px">
                       </td>
                       <td style="width: 100px">
                            <asp:TextBox ID="txtNumber_rn" runat="server"></asp:TextBox></td>
                  </tr>
                  <tr>
                       <td style="width: 100px">
                            Date</td>
                       <td style="width: 100px">
                            <asp:Calendar ID="Calendar1" runat="server"></asp:Calendar>
                       </td>
                       <td style="width: 100px">
                            <asp:TextBox ID="txtDate_rd" runat="server"></asp:TextBox></td>
                  </tr>
                  <tr>
                       <td style="width: 100px">
                            <asp:Button ID="btnValidateForm" runat="server" OnClick="btnValidateForm_Click" Text="Validate Form"
                                 Width="100px" /></td>
                       <td style="width: 100px">
                       </td>
                       <td style="width: 100px">
                       </td>
                  </tr>
                  <tr>
                       <td colspan="3" style="height: 164px">
                            <asp:ListBox ID="lstMessages" runat="server" Height="154px" Width="471px" OnSelectedIndexChanged="lstMessages_SelectedIndexChanged"></asp:ListBox></td>
                  </tr>
             </table>
        </div>
    </form>
</body>
</html>


////////////////////////////////DEFAULT.CS
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;

public partial class _Default : System.Web.UI.Page
{
     private static IDictionary<string, string> controlTitleMapping = new Dictionary<string, string>();

     private void populateControlTitleMapping( )
     {
          controlTitleMapping.Add( "txtDate_rd", "Date" );
          controlTitleMapping.Add( "txtEmail_re", "Email" );
          controlTitleMapping.Add( "txtLength_rl", "Length" );
          controlTitleMapping.Add( "txtNumber_rn", "Number" );
          controlTitleMapping.Add( "txtRequired_r", "Required" );
     }

     protected void Page_Load( object sender, EventArgs e )
     {

          //Populate Dictionary object with values used to identify each field on the form
          //in a user friendly manner. Used when validation messages are displayed.
          if ( !IsPostBack )
          {
               populateControlTitleMapping();
          }

     }

     protected void lstMessages_SelectedIndexChanged( object sender, EventArgs e )
     {

     }

     protected void btnValidateForm_Click( object sender, EventArgs e )
     {
          lstMessages.Items.Clear();
          displayMessages(
                                        FormValidator.validateForm( Page.Form, controlTitleMapping )
                                      );
     }

     private void displayMessages( List<ValidatedField> msgs )
     {
          foreach ( ValidatedField vf in msgs )
               foreach ( String msg in vf.getAllValidationMessages() )
                    lstMessages.Items.Add( new ListItem(  msg, msg ) );
     }
}
0
 
LVL 3

Author Comment

by:baijajusav
ID: 22606184
//////////////////////////////////////IN APP CODE ................ FormValidator.cs
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Reflection.Emit;
using System.Reflection;

/// <summary>
/// Summary description for FormValidator
/// </summary>
public class FormValidator
{
     public FormValidator( )
     {
          //
          // TODO: Add constructor logic here
          //
     }

     public static List<ValidatedField> validateForm( HtmlForm form, IDictionary<string, string> pControlTitleMapping )
     {
          List<ValidatedField> validatedFields = new List<ValidatedField>();

          //Iterate over all controls on the form
          foreach ( Control c in form.Controls )
          {

               //if a underscore is present then validator subscripts are in the name of the control
               if ( c.ID != null && c.ID.Contains( "_" ) )
               {
                    ValidatedField vf = new ValidatedField();
                    vf.ServerControlName = c.ID;
                    vf.FormControlName = c.UniqueID;
                    vf.MessageDisplayName = pControlTitleMapping[ c.ID ];
                    //Look up phrasing to be used for error messages that refer to this control
                    String fieldName = pControlTitleMapping[ c.ID ];
                    String fieldValue = null;
                    String validationMessage = null;
                    string[ ] parts = c.ID.Split( '_' );
                    string validations = parts[ 1 ];

                    //Try casting the current control to its true type so that we may
                    //retrieve its value in order to validate it. This approach has obvious drawbacks,
                    //but for now, it's all I have.
                    if ( c is TextBox )
                    {
                         TextBox tb = ( TextBox ) c;
                         fieldValue = tb.Text;
                    }
                    else if ( c is DropDownList )
                    {
                         DropDownList dl = ( DropDownList ) c;
                         fieldValue = dl.SelectedValue;

                    }
                    else if ( c is ListBox )
                    {
                         ListBox lb = ( ListBox ) c;
                         fieldValue = lb.SelectedValue;
                    }
                    else if ( c is System.Web.UI.WebControls.Label )
                    {
                         System.Web.UI.WebControls.Label label = ( System.Web.UI.WebControls.Label ) c;
                         fieldValue = label.Text;
                    }
                    else if ( c is CheckBoxList )
                    {
                         CheckBoxList chkList = ( CheckBoxList ) c;
                         fieldValue = chkList.SelectedValue;
                    }
                    else if ( c is RadioButtonList )
                    {
                         RadioButtonList radBtnList = ( RadioButtonList ) c;
                         fieldValue = radBtnList.SelectedValue;
                    }
                    else
                    {
                         //We have no value for the control in this iteration; hence, no validation can take place.
                    }

                    //Controls may have more than one validation. Iterate over the subscripts.
                    foreach ( char ch in validations )
                    {
                         validationMessage = null;

                         //do the appropriate validation for the given subscript
                         switch ( ch.ToString() )
                         {
                              case "r":
                                   validationMessage = validateRequired( fieldName, fieldValue );
                                   if ( validationMessage != null )
                                        vf.AddValidationMessage( validationMessage );
                                   break;
                              case "e":
                                   break;
                              case "l":
                                   break;
                              case "d":
                                   validationMessage = validateDate( fieldName, fieldValue );
                                   if ( validationMessage != null )
                                        vf.AddValidationMessage( validationMessage );
                                   break;
                              case "n":
                                   validationMessage = validateNumeric( fieldName, fieldValue );
                                   if ( validationMessage != null )
                                        vf.AddValidationMessage( validationMessage );
                                   break;
                              case "x":
                                   break;
                              default:
                                   break;

                         }  // end switch/case statement                        

                    } // end foreach loop of validation subscripts

                    validatedFields.Add( vf );

               } // end check to see if this control's id contain's subscripts that indicate field validations to be performed

          } // end foreach loop of controls contained in the form object passed to this method

          return validatedFields;
     }

     /// <summary>
     /// Performs validation that determines a field has a value.
     /// </summary>
     /// <param name="fieldName">Name used for a control when referencing an error pertaining to that controls value (or lack thereof).</param>
     /// <param name="fieldValue">Value of the control being validated.</param>
     /// <returns></returns>
     private static String validateRequired( String fieldName, String fieldValue )
     {
          if ( fieldValue == null || fieldValue.Trim().Length <= 0 )
          {
               return fieldName + " is required.";
          }
          return null;
     }

     /// <summary>
     /// Performs validation that tests the value of a control or field to ensure it is
     /// in proper date format.
     /// </summary>
     /// <param name="fieldName">Name used for a control when referencing an error pertaining to that controls value (or lack thereof).</param>
     /// <param name="fieldValue">Value of the control being validated.</param>
     /// <returns></returns>
     private static String validateDate( String fieldName, String fieldValue )
     {
          DateTime d;
          if ( fieldValue == null || fieldValue.Trim().Length <= 0 )
          {
               return fieldName + " must be a valid date in mm/dd/yyyy format.";
          }
          else if ( !DateTime.TryParse( fieldValue, out d ) )
          {
               return fieldName + " must be a valid date in mm/dd/yyyy format.";
          }
          return null;
     }


     /// <summary>
     /// Performs validation that tests the field value to ensure it is numeric.
     /// </summary>
     /// <param name="fieldName">Name used for a control when referencing an error pertaining to that controls value (or lack thereof).</param>
     /// <param name="fieldValue">Value of the control being validated.</param>
     /// <returns></returns>
     private static String validateNumeric( String fieldName, String fieldValue )
     {
          Int64 lng;
          double dbl;
          if ( fieldValue == null || fieldValue.Trim().Length <= 0 )
          {
               return fieldName + " must be numeric.";
          }
          else if ( !Int64.TryParse( fieldValue, out lng ) && !double.TryParse( fieldValue, out dbl ) )
          {
               return fieldName + " must be numeric.";
          }
          return null;
     }

     /// <summary>
     /// Performs validation that tests the field value to ensure it is non-numeric/alpha.
     /// </summary>
     /// <param name="fieldName">Name used for a control when referencing an error pertaining to that controls value (or lack thereof).</param>
     /// <param name="fieldValue">Value of the control being validated.</param>
     /// <returns></returns>
     private static String validateNonNumeric( String fieldName, String fieldValue )
     {
          Int64 lng;
          if ( fieldValue == null || fieldValue.Trim().Length <= 0 )
          {
               return fieldName + " must be non-numeric.";
          }
          else if ( Int64.TryParse( fieldValue, out lng ) )
          {
               return fieldName + " must be non-numeric.";
          }
          return null;
     }

}


/////////////////////////////////////////////// IN APP CODE ... ValidatedField.cs
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Collections.Generic;

/// <summary>
/// Summary description for ValidatedField
/// </summary>
public class ValidatedField
{
     public ValidatedField( )
     {
          validationMessages = new List<String>();
     }

     private String serverControlName;
     private String formControlName;
     private String messageDisplayName;
     private List<String> validationMessages;

     /// <summary>
     /// Adds a validation message to this ValidatedField's
     /// List of validation messages.
     /// </summary>
     /// <param name="msg">A String containing the validation message.</param>
     public void AddValidationMessage( String msg )
     {
          validationMessages.Add( msg );
     }

     /// <summary>
     /// Retrieves all validation messages for a given ValidatedField
     /// object.
     /// </summary>
     /// <returns>A List<String> containing validation messages. </returns>
     public List<String> getAllValidationMessages( )
     {
          return validationMessages;
     }

     /// <summary>
     /// Refers to the id of a server control.
     /// </summary>
     public String ServerControlName
     {
          get
          {
               return serverControlName;
          }
          set
          {
               serverControlName = value;
          }
     }

     /// <summary>
     /// Refers to the unique form id of a control.
     /// </summary>
     public String FormControlName
     {
          get
          {
               return formControlName;
          }
          set
          {
               formControlName = value;
          }
     }

     /// <summary>
     /// Refers to Name used when referencing a given control
     /// in a validation message. These correlate to given server control's,
     /// though, the phrasing of the name will be different.
     /// </summary>
     public String MessageDisplayName
     {
          get
          {
               return messageDisplayName;
          }
          set
          {
               messageDisplayName = value;
          }
     }

}


///////////////////////////////////////// web.config
<?xml version="1.0"?>
<!--
    Note: As an alternative to hand editing this file you can use the
    web admin tool to configure settings for your application. Use
    the Website->Asp.Net Configuration option in Visual Studio.
    A full list of settings and comments can be found in
    machine.config.comments usually located in
    \Windows\Microsoft.Net\Framework\v2.x\Config
-->
<configuration>
      <appSettings/>
      <connectionStrings/>
      <system.web>
            <!--
            Set compilation debug="true" to insert debugging
            symbols into the compiled page. Because this
            affects performance, set this value to true only
            during development.
        -->
            <compilation debug="true"/>
            <!--
            The <authentication> section enables configuration
            of the security authentication mode used by
            ASP.NET to identify an incoming user.
        -->
            <authentication mode="Windows"/>
            <!--
            The <customErrors> section enables configuration
            of what to do if/when an unhandled error occurs
            during the execution of a request. Specifically,
            it enables developers to configure html error pages
            to be displayed in place of a error stack trace.

        <customErrors mode="RemoteOnly" defaultRedirect="GenericErrorPage.htm">
            <error statusCode="403" redirect="NoAccess.htm" />
            <error statusCode="404" redirect="FileNotFound.htm" />
        </customErrors>
        -->
      </system.web>
</configuration>
0
 
LVL 3

Author Comment

by:baijajusav
ID: 22606225

I don't know if the code above would help anyone, but I give permission for all to freely use for any reasons what-so-ever, commercial or otherwise. I would appreciate some comments/suggestions/revisions though.

Thanks for all of your time.
0
Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 
LVL 26

Expert Comment

by:Anurag Thakur
ID: 22611449
seriously i dont think its a good way of doing things.
first i recommend you to use asp.net validator controls (becasue the first level of checks are done by them at the client side and client side valiation is a faster way of doing validation)

if somehow the client side validation is skipped/ignored then you should do server side validations

but your logic of adding a suffix to the ID of the control and then doing a split is just going to slow the things down as un-necessary string objects are created which dont free up the memory used by them so easily.

my recommendation use validation controls and where validations have to be done on the server side use customvalidators

Most of the validations can be achieved by using requiredfield validators and regular expression validators

best of luck
0
 
LVL 3

Author Comment

by:baijajusav
ID: 22613575

That is very true, but it requires you to bind your validation phrasing to the presentation layer. Furthermore, it is quite cumbersome to add 1 or more controls per validation. On large forms you could end up having an equal number of validator controls or more to the number of fields on the page. That hardly seems realistic or maleable.

I agree wholeheartedly that this method of validation has many short comings; however, it does satisfy the requirement of being easily reusable.

I'm currently looking into the Spring .Net Validator framework as an option. If any one has some resources regarding this, it would be greatly appreciated. I'm namely looking for a demo .net project that has the validation working.
0
 
LVL 3

Author Comment

by:baijajusav
ID: 22613592
I do want you to know that, while we might disagree, I sincerely appreciate your comments. I know that's a wall of code and wish I could have just attached the project. Thanks for wading through it.
0
 
LVL 26

Accepted Solution

by:
Anurag Thakur earned 500 total points
ID: 22618799
the opinions might be different and i totally appreciate that
but my only concern is that in a web application the first level of validations are normally performed on the client side so that the round trip to the server is saved if something is missing but by your logic the round trip will always be made so their will be considerable delay in things

anyways thats my view point might not be the best one
0

Featured Post

Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

Join & Write a Comment

This article is for Object-Oriented Programming (OOP) beginners. An Interface contains declarations of events, indexers, methods and/or properties. Any class which implements the Interface should provide the concrete implementation for each Inter…
It was really hard time for me to get the understanding of Delegates in C#. I went through many websites and articles but I found them very clumsy. After going through those sites, I noted down the points in a easy way so here I am sharing that unde…
It is a freely distributed piece of software for such tasks as photo retouching, image composition and image authoring. It works on many operating systems, in many languages.
Internet Business Fax to Email Made Easy - With eFax Corporate (http://www.enterprise.efax.com), you'll receive a dedicated online fax number, which is used the same way as a typical analog fax number. You'll receive secure faxes in your email, fr…

747 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now