Advanced Validators: validazione a gruppi

di Cristian Civera, in ASP.NET,

Chiunque cominci a sviluppare con ASP.NET avrà senz'altro gradito molto i validatori che ci mette a disposizione. Con poche righe si creano form e validatori di campi dinamici, con l'aggiunta di codice JavaScript.

Sviluppando applicazioni web sempre più complicate, però, si è presentato un limite: non è possibile indicare quali controlli devono essere validati e quali no.

In un'applicazione reale, una pagina web può presentare più moduli, ad esempio per login, sondaggi, registrazioni, ecc, e nell'attuale implementazione ogni PostBack automaticamente scatena la validazione di tutti i controls della pagina

In questo articolo svilupperemo un insieme di componenti volti a colmare questa mancanza del Framework.

Genesi degli Advanced Validators

Quello che faremo non sarà altro che estendere i controlli già esistenti aggiungendo una proprietà "GroupName", che sfrutteremo per raggruppare i controlli, un po' come succede con ASP.NET 2.0 .

Per fare ciò dobbiamo prima conoscere il funzionamento dei validators ASP.NET. Come già sapete le classi contenute nel namespace System.Web.WebControls sono:

  • RequiredFieldValidator
  • RegularExpressionValidator
  • CustomValidator
  • CompareValidator
  • RangeValidator

Tutti questi controllo ereditano da BaseValidator che contiene le funzionalità comuni dei validators. Per approfondire la trattazione dei validators, vi rimando a questo articolo .

La validazione di una pagina, come si può leggere nell'articolo appena segnalato, si divide in due parti:

  • lato server, con codice ovviamente .Net
  • lato client, mediante JavaScript e DHTML

Passiamo quindi a vedere in dettaglio come implementare la nostra soluzione.

La validazione lato server

Ogni qual volta istanziamo un validatore questo, in fase di init, si autoaggiunge alla collezione Validators della classe Page, al fine di mantenere una lista dei validatori della pagina.

Quando richiamiamo il metodo Page.Validate() o interroghiamo la proprietà Page.IsValid viene sfogliata questa collezione ed interrogata la proprietà IsValid (interfaccia IValidator implementata da BaseValidator). Questa proprietà è impostata dal metodo astratto EvaluateIsValid che ogni controllo, tra quelli citati, definisce a seconda della validazione da eseguire.

Per la nostra esigenza quindi, dobbiamo dotare ognuno dei validatori della proprietà GroupName e sovrascrivere EvaluateIsValid in modo che dia sempre un risultato positivo se il gruppo da validare è diverso da quello a cui il controllo appartiene o un risultato veritiero ricavato dal metodo base se il gruppo da validare è lo stesso di quello a cui il controllo appartiene.

Definiamo quindi un'interfaccia (per comodità) che ogni validatore "a gruppo" dovrà implementare.

public interface IAdvancedValidator
 {
  string GroupName {get;set;}
 }

Dobbiamo però informare il validator quale gruppo stiamo validando. Come sapete, i controlli Button, LinkButton e ImageButton dispongono di una proprietà CausesValidation, poiché sono loro che invocano il metodo Page.Validate() per validare la pagina. Perciò dobbiamo dotare questi controlli di una proprietà per indicare il gruppo, anche in questo caso definendo un'interfaccia:

public interface IAdvancedValidatorButton
 {
  string ValidationGroupName {get;set;}
 }

A questo punto dobbiamo creare un nostro controllo che erediti da uno dei tanti validatori, per esempio il RequiredFieldValidator e applicare quanto appena detto:

public class RequiredFieldValidator : System.Web.UI.WebControls.RequiredFieldValidator, IAdvancedValidator
 {
  public RequiredFieldValidator()
  {
  }
 
  protected override bool EvaluateIsValid()
  {
    if (AdvancedValidatorUtil.GetCurrentValidationGroupName(this.Page) == GroupName)
     return base.EvaluateIsValid();
    else
     return true;
  }
 
  [Category("Behavior"),
  DefaultValue("group1"),
  Description("Indica il gruppo di validazione a cui appartiene"),
  TypeConverter(typeof(GroupNameConverter))]
  public string GroupName
  {
    get
    {
     object o = ViewState["GroupName"];
     if (o == null)
      return String.Empty;
     return (string)o;
    }
    set
    {
     ViewState["GroupName"] = value;
    }
  }
  
 }

E quindi un un bottone che implementa l'altra interfaccia:

public class Button : System.Web.UI.WebControls.Button, IAdvancedValidatorButton
 {
  public Button()
  {
  }
   [Category("Behavior"),
  DefaultValue("group1"),
  Description("Indica il gruppo di validazione che deve validare"),
  TypeConverter(typeof(GroupNameConverter))]
  public string ValidationGroupName
  {
    get
    {
     object o = ViewState["VGN"];
     if (o != null)
      return (string)o;
     return String.Empty;
    }
    set
    {
     ViewState["VGN"] = value;
    }
  }
  }

In particolare abbiamo ridefinito il metodo EvaluateIsValid, che controlla se il gruppo di appartenenza coincide con quello da validare, sfruttando il metodo statico GetCurrentValidationGroupName:

internal static string GetCurrentValidationGroupName(Page page)
 {
  HttpContext context = HttpContext.Current;
   string group = (string)context.Items["AdvancedValidatorsGroupName"];
  if (group == null)
  {
    IAdvancedValidatorButton c = GetControlPostBacker(page) as IAdvancedValidatorButton;
    if (c != null)
     SetCurrentValidationGroupName(c.ValidationGroupName);
    group = (string)context.Items["AdvancedValidatorsGroupName"];
  }
  return group;
 }
 
 public static void SetCurrentValidationGroupName(string validationGroupName)
 {
  HttpContext.Current.Items["AdvancedValidatorsGroupName"] = validationGroupName;
 }

In pratica controlliamo se il webcontrol che ha scatenato il post (per informazioni si veda lo script #576 ) implementa la nostra interfaccia, preleviamo il nome del gruppo e lo salviamo nel contesto della richiesta.

2 pagine in totale: 1 2

Attenzione: Questo articolo contiene un allegato.

Contenuti dell'articolo

Commenti

Visualizza/aggiungi commenti

| Condividi su: Twitter, Facebook, LinkedIn

Per inserire un commento, devi avere un account.

Fai il login e torna a questa pagina, oppure registrati alla nostra community.

Approfondimenti