WCSF Validation Tweaks

January 29th, 2008

We recently implemented the Validation Bundle from P&P. The Bundle consists of the VAB PropertyProxyValidator from EntLib, as well as a custom ASP.NET AJAX control extender which provides the client callback support.

For the most part the Bundle rocks, but there are a few things which didn’t meet our needs:

  1. The default PropertyProxyValidator inherits from System.Web.UI.WebControls.BaseValidator, like the other Asp.Net validators. This makes it great for mixing all types of standard Validators (Like Regex or RequiredField), but has a major drawback for Client side validation because it validates on every PostBack (full) as well as Callback (partial).
  2. On a full postback, such as a form submit, the ServerSideValidationExtender issues a Callback request to the Validator
  3. Even if the value had not changed, validation still occurs.

A simple scenario

We have an Organization with two fields, Name & Code

image

Lets look at the validation events:

  • Enter Name ‘Bob’s Plumbing’, Press Tab (or click off)
    • Callback: Validation occurs for Name
  • Enter Code ‘BPL’, Press Tab (or click off)
    • Callback: Validation occurs for Code
  • Click Save
    • Callback: Validation occurs for Name
    • Callback: Validation occurs for Code
    • Postback (full): Validation Occurs for Name & Code

So we have validated each property 3 times. This might be OK we were just parsing for special characters, but in our case we also want to call a service and see if these values already exist in our system: 3x is too expensive.

Aside from being expensive, this is a unique type of validation where we want to check if a condition isn’t true (Org Name doesn’t exist) vs. is true. (an valid email address or a valid state)

This makes point #3 above especially troubling for our scenario, because if we want to edit this Organization in the future, any time we change a value, all the rest of the validators will fire and come back invalid as they already exist.

Example updating just the Org Code, which causes the Name to validate:

image

 

The Solution

  • Kill the full postback validation with OnCallBackPropertyProxyValidator
  • Modify ServerSideValidationExtender to *only* validate if the value has changed

OnCallBackPropertyProxyValidator

OnCallBackPropertyProxyValidator is a pretty quick fix. We will just inherit the ProperyProxyValidator and kick out of the EvaluateIsValid method if its not a CallBack.

 

   1:    /// <summary>
   2:    /// Class which only performs validation when page is in a callback state
   3:    /// </summary>
   4:    public class OnCallBackPropertyProxyValidator : PropertyProxyValidator
   5:    {
   6:        /// <summary>
   7:        /// If Page.IsCallBack, determines whether the content in the input control is valid.
   8:        /// </summary>
   9:        /// <returns><see langword="true"/> if the control is valid; otherwise, <see langword="false"/>.</returns>
  10:        protected override bool EvaluateIsValid()
  11:        {
  12:            if (!this.Page.IsCallback)
  13:            {
  14:                this.ErrorMessage = "";
  15:                return true;
  16:            }
  17:            else 
  18:            {
  19:                return base.EvaluateIsValid();
  20:            }
  21:        }
  22:    }

 

ServerSideValidation

Well add the ‘only-validate-if-value-changed’ functionality by fetching the current text value from the control to be validated, storing the property in JSON, and then evaluating if the value has changed before requesting validation from the server.

 

Modifying the ServerSideValidationExtender.cs

Add the CurrentValue Property to the Extender C# class:

 

   1: [ExtenderControlProperty]
   2: [ClientPropertyName("currentValue")]
   3: [DefaultValue("")]
   4: public string CurrentValue
   5: {
   6:     get { return GetPropertyValue<string>("CurrentValue", string.Empty); }
   7:     set { SetPropertyValue<string>("CurrentValue", value); }
   8: }

Set the current value in OnPreRender:

 

   1: protected override void OnPreRender(EventArgs e)
   2:     {
   3:         base.OnPreRender(e);
   4:        
   5:         Omitted code here....        
   6:  
   7:         // Set the current Text value
   8:         Control controlToValidate = extendedValidator.NamingContainer.FindControl(extendedValidator.ControlToValidate);
   9:         ITextControl textControl = controlToValidate as ITextControl;
  10:         if (textControl != null)
  11:         {
  12:             CurrentValue = textControl.Text;
  13:         }
  14:         
  15:         Omitted code here...
  16:     }

 

Modifying the ServerSideValidationBehavior.js Behavior

Add the CurrentValue property to the descriptor:

 

   1: AjaxControlToolkit.WCSFExtensions.ServerSideValidationBehavior.descriptor = {
   2:    properties: [   {name: 'callbackControl', type: String},
   3:                    {name: 'validateEmptyText', type: Boolean},
   4:                    {name: 'currentValue', type: String} ]
   5: }

Add the accessor methods to the prototype:

 

   1: get_currentValue: function(){
   2:     return this.currentValue;
   3: },
   4: set_currentValue: function(value){
   5:     this.currentValue = value;
   6: }

And finally check to see if the value has changed

   1: Validate: function() {
   2:     var valueToValidate = this._getValueToValidate();
   3:  
   4:     Omitted....
   5:  
   6:     if (valueToValidate === this.get_currentValue()) {
   7:         return true;
   8:     }
   9:     
  10:     Omitted.... 
  11:     
  12: },

And that’s it. What we end up with is client side validation which only occurs when the value is changed on the client, through a callback, and no where else. All other validation works in tandem as expected, such as the standard ASP.NET validators, PropertyProxyValidator, or a custom validator which performs VAB self validation.

Though the Bundle didn’t do everything we were looking for right out of the box, it was pretty easy to get in there and make work exactly how we wanted. Hats off to P&P for some great guidance.

The source code is here. Its just the files, not a complete working solution, but if you download the WCSF source/ Validation Bundle you should be able to plug it in fairly easily.

 

Technorati Tags: ,,,