Introduction
A modern and user friendly web application will recognize invalid user input as early as possible and will signal such
conditions to the user. For the ASP.NET Framework there exist various controls for the validation of user input.
These validators spring into action in the browser on the user's computer and thus prevent time and resource intensive
requests to the web server.
In real world scenarios these validators will only suffice for simple applications. Very quickly a point is reached,
where the development of a specialized validator becomes unavoidable. Doing so requires to implement the necessary validation
functionality both in C# resp. VB.NET for the server side as well as in JavaScript for the client side. Both implementations
reflect the same validation logic. In general, the JavaScript Code will be generated by C#/VB.NET code, which can make maintenance
and documentation of such validators complicated.
The component introduced here extends the ASP.NET validators by a simple rule framework, covering the following functionality:
- Validation of checkboxes and radio buttons
- Atomic validation of multiple input values
- Validation of input according to logical conditions
- Variable definition of validation rules
- Incorporation of the standard ASP.NET validators
- No additional JavaScript code required
Realization of this component was inspired by the excellent article
Multiple Fields Validator - An ASP.NET Validation Control by Adam Tibi.
Custom Control Validation
The validators contained in ASP.NET can only be applied to controls which have been marked with the ValidationProperty
.
The validation of user input can require to ensure validity depending on the state of checkboxes and radio buttons. Unfortunately,
the corresponding .NET controls are not validatable by default and have to be extended by own derivations to support this.
For this purpose, the accompanying library contains the controls ValidatableRadioButton
and ValidatableCheckBox
:
[ValidationProperty( "ValidationValue" )]
public class ValidatableCheckBox : CheckBox
{
public string ValidationValue
{
get { return ( Checked ? bool.TrueString : bool.FalseString ); }
}
}
Note: These extensions are designed for rule based validation and cannot be used in conjunction with the standard ASP.NET validators.
Solution Approach
The graphical overview shows the workflow of the rule validation. Validation is triggered by the Validation Trigger - which is most
commonly a button. According to the validator property EnableClientScript
it is determined whether client side validation will occur.
This value is set to true
by default and should only be changed in exceptional situations.
In Evaluate Rules follows the client side checking of the rules defined in the validator. With JavaScript the input values will
be checked against the rules of the validator. According to the validation type (prescription/prohibition) it is determined whether validation
succeeded or failed.
In case validation failed, a client side generated error message is displayed and will lead to the abortion of the user request.
With succeeding client side validation, the user request is sent to the web server, where Evaluate Rules will perform the same
validation sequence checking in C#/VB.NET. Failing to pass this, a corresponding error message will be displayed in the web client.
In case the server side validation succeeds as well, further processing of the request is guaranteed to operate on valid input data.
Each rule is described by the following properties:
Operation
: The calculation logic of the rule Scope
: The controls to be considered by the rule
The controls are being referenced in form of a comma separated list of IDs Source
: The source of the data to validate
The rule applies to the value of the control (default) or its selection (ValidatableRadioButton
or ValidatableCheckBox
) CompareValue
: The value to compare in the rule
This value will be compared with the content of the control (default=empty text) CompareCount
: The count to validate in the rule
The count only applies to certain rule operations (see further below)
Invalid control references in Scope
or an invalid count in CompareCount
will be detected by the system and
result in a runtime exception.
Rule Operation
The possible rule operations are defined in the enumeration RuleOperation
:
Operation | Description | Scope Target | Scope Count | Value Condition | Option Condition |
AtLeastOne | At least one is matching (OR) | Validatable Control | 2+ | CompareValue | Is selected |
None | None is matching (NOR) | Validatable Control | 2+ | CompareValue | Is selected |
OneOfTwo | One of two is matching (XOR) | Validatable Control | 2 | CompareValue | Is selected |
All | All are matching (AND) | Validatable Control | 2+ | CompareValue | Is selected |
AtLeastNotOne | At least one is not matching (NAND) | Validatable Control | 2+ | CompareValue | Is selected |
Count | A specific count is matching | Validatable Control | 2+ | CompareValue and CompareCount | Is selected and CompareCount |
MinCount | A minimum count is matching | Validatable Control | 2+ | CompareValue and CompareCount | Is selected and CompareCount |
MaxCount | A maximum count is matching | Validatable Control | 2+ | CompareValue and CompareCount | Is selected and CompareCount |
NotCount | A speficic count is not matching | Validatable Control | 2+ | CompareValue and CompareCount | Is selected and CompareCount |
Equals | A value is matching | Validatable Control | 1 | CompareValue | Is selected |
NotEquals | A value is not matching | Validatable Control | 1 | CompareValue | Is selected |
Expression | An expression is matching | Validatable Control | 1 | RegEx of CompareValue | Not supported |
NotExpression | An expression is not matching | Validatable Control | 1 | RegEx of CompareValue | Not supported |
RequiredFieldValidator | A RequiredFieldValidator is valid | Validator Control | 1 | Validator result | Not supported |
NotRequiredFieldValidator | A RequiredFieldValidator is invalid | Validator Control | 1 | Validator result | Not supported |
CompareValidator | A CompareValidator is valid | Validator Control | 1 | Validator result | Not supported |
NotCompareValidator | A CompareValidator is invalid | Validator Control | 1 | Validator result | Not supported |
RangeValidator | A RangeValidator is valid | Validator Control | 1 | Validator result | Not supported |
NotRangeValidator | A RangeValidator is invalid | Validator Control | 1 | Validator result | Not supported |
RegularExpressionValidator | A RegularExpressionValidator is valid | Validator Control | 1 | Validator result | Not supported |
NotRegularExpressionValidator | A RegularExpressionValidator is invalid | Validator Control | 1 | Validator result | Not supported |
CustomValidator | A CustomValidator is valid | Validator Control | 1 | Validator result | Not supported |
NotCustomValidator | A CustomValidator is invalid | Validator Control | 1 | Validator result | Not supported |
Scope Count
describes the number of allowed control references. An invalid number of scope references will
lead to a runtime exception.
Validation Type
The validation type determines how the result of the rule validation should be interpreted:
Prescription
: The rules describe a state which has to be adhered to
In case the input matches to the rules, validation is valid (default) Prohibition
: The rules describe a state which is not allowed
In case the input matches to the rules, validation is invalid
Which validation type makes sense depends on the scenario at hand. The following examples demonstrate the
validation type with several concrete real world examples.
Validation Controls
The library attached to the article contains two validation controls:
RuleValidator
: a validator with a single rule MultiRuleValidator
: a validator with an arbitrary number of rules
The RuleValidator
is intended for simple scenarios where validation is achieved by a single rule.
The following example enforces at least one text input:
<asp:TextBox runat="server" ID="Edit1" />
<asp:TextBox runat="server" ID="Edit2" />
<asp:TextBox runat="server" ID="Edit3" />
<val:RuleValidator runat="server" Display="None" ErrorMessage="Please enter at least one text"
Operation="AtLeastOne" Scope="Edit1,Edit2,Edit3" />
<asp:ValidationSummary runat="server" />
<asp:Button runat="server" Text="Submit" OnClick="SubmitClick" />
Using the MultiRuleValidator
it is possible to combine multiple rules in one validation.
The validator is considered valid when all rules are fulfilled (logic AND).
The following login example allows a user to either login with existing credentials or to register.
In case of an existing user the presence of password input is checked:
<asp:Label runat="server" Text="E-Mail:" />
<asp:TextBox runat="server" ID="EmailEdit" />
<br />
<val:ValidatableRadioButton runat="server" ID="NewCustomerOption" Text="New Customer"
GroupName="LoginGroup" Checked="True" />
<br />
<val:ValidatableRadioButton runat="server" ID="ExistingCustomerOption" Text="Password:"
GroupName="LoginGroup" />
<asp:TextBox runat="server" ID="PasswordEdit" />
<val:RuleValidator runat="server" Display="None" ErrorMessage="Please enter a valid E-Mail address"
Scope="EmailEdit" Operation="Expression" CompareValue="\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*" />
<val:MultiRuleValidator runat="server" Display="None" ErrorMessage="Please enter your password"
ValidationType="Prohibition">
<val:Rule Operation="Equals" Scope="ExistingCustomerOption" Source="Option" CompareValue="True" />
<val:Rule Operation="Equals" Scope="PasswordEdit" CompareValue="" />
</val:MultiRuleValidator>
<asp:ValidationSummary runat="server" />
<asp:Button runat="server" Text="Login" OnClick="LoginClick" />
The next example demonstrates how to enforce a valid credit card number depending on the credit card type.
For each credit card type, the input is validated according to a specific regular expression:
<asp:Label runat="server" Text="Credit Card:" />
<asp:ListBox runat="server" ID="CardList">
<asp:ListItem Text="Visa" Value="Visa" />
<asp:ListItem Text="Master Card" Value="MasterCard" />
<asp:ListItem Text="American Express" Value="AmericanExpress" />
</asp:ListBox>
<asp:TextBox runat="server" ID="CardEdit" />
<asp:RequiredFieldValidator runat="server" ErrorMessage="Please select the Card" Display="None"
ControlToValidate="CardList" />
<val:MultiRuleValidator runat="server" Display="None" ErrorMessage="Invalid Visa Number"
ValidationType="Prohibition">
<val:Rule Operation="Equals" Scope="CardList" CompareValue="Visa" />
<val:Rule Operation="NotExpression" Scope="CardEdit" CompareValue="^4[0-9]{12}(?:[0-9]{3})?$" />
</val:MultiRuleValidator>
<val:MultiRuleValidator runat="server" Display="None" ErrorMessage="Invalid Master Card Number"
ValidationType="Prohibition">
<val:Rule Operation="Equals" Scope="CardList" CompareValue="MasterCard" />
<val:Rule Operation="NotExpression" Scope="CardEdit" CompareValue="^5[1-5][0-9]{14}$" />
</val:MultiRuleValidator>
<val:MultiRuleValidator runat="server" Display="None" ErrorMessage="Invalid American Express Number"
ValidationType="Prohibition">
<val:Rule Operation="Equals" Scope="CardList" CompareValue="AmericanExpress" />
<val:Rule Operation="NotExpression" Scope="CardEdit" CompareValue="^3[47][0-9]{13}$" />
</val:MultiRuleValidator>
<asp:ValidationSummary runat="server" />
<asp:Button runat="server" Text="Submit" OnClick="SubmitClick" />
Composite Validation
To cover scenarios with even more requirements it is possible to incorporate the standard ASP.NET validators
into the rule framework. By assigning the corresponding Operation
and referencing the validator via
Scope
, it is very easy to reuse the functionality of the standard ASP.NET validators:
<val:ValidatableCheckBox runat="server" ID="TimeRangeOption" Text="Restrict to time range" />
<br />
<asp:Label runat="server" Text="From: " />
<asp:TextBox runat="server" ID="StartEdit" />
<asp:Label runat="server" Text="Until: " />
<asp:TextBox runat="server" ID="EndEdit" />
<asp:CompareValidator runat="server" ID="TimeRangeValidator" Type="Date" Operator="LessThan"
ControlToValidate="StartEdit" ControlToCompare="EndEdit" />
<val:MultiRuleValidator runat="server" Display="None" ErrorMessage="Invalid time range"
ValidationGroup="SettingValidation" ValidationType="Prohibition">
<val:Rule Operation="Equals" Scope="TimeRangeOption" Source="Option" CompareValue="True" />
<val:Rule Operation="NotCompareValidator" Scope="TimeRangeValidator" />
</val:MultiRuleValidator>
<asp:ValidationSummary runat="server" ValidationGroup="SettingValidation" />
<asp:Button runat="server" Text="Save" ValidationGroup="SettingValidation" OnClick="SaveClick" />
When using composite validators it important to ensure that the referenced validators will not be run multiple times.
This can be prevented by putting the rule validator into a separate ValidationGroup
.
The rule validators can also be used in cases where multiple standard ASP.NET validators should be combined
into an atomic rule according to variable criteria.
Points of Interest and Delimitations
- The required JavaScript code on client side is an embedded resource of the library and is being loaded into the web browser as a WebResource
- Within the page validation, the rule validators can be combined as desired with the standard ASP.NET validators
- Validation of the control
CheckBoxList
is currently not supported - Further information in regard to ASP.NET validation can be found under MSDN,
MSDN and MSDN
History
- 18th April, 2012: Initial release - v1.1.0.0
- new rule operations
MinCount
and MaxCount
- new example: product selection
- 17th April, 2012: Initial release - v1.0.0.0