La persistenza delle proprietà di un WebControl senza utilizzare il Postback

Chi programma in ASP.Net sin dalle prime versioni ha iniziato da subito ad apprezzare e contemporaneamente ad odiare lo StateBag delle pagine, altrimenti chiamato ViewState. Senza scendere troppo nei particolari, altrimenti andrei fuori tema, il ViewState non fa altro che serializzare il contenuto delle variabili di una pagina all’interno di una stringa che si passa attraverso le successive richieste mediante postback.

Il dramma del ViewState è per l’appunto che magari pur non necessario per tutti i controlli (anche annidati) è necessario mantenerlo attivo affinchè questo processo di persistenza possa funzionare. Questo significa il più delle volte trasmettere una enorme quantità di dati da e verso il server, che non tutti gli scenari possono supportare.

Nasce così, con il framework e ASP.Net 2.0 un nuovo metodo di persistenza definitico ControlState, che funziona sullo stesso principio del ViewState, ma a differenza di quest’ultimo è indipendente, non è disattivabile da parte dell’utente e memorizza solo lo stretto necessario (in virtù chiaramente degli override che compiete nel vostro codice), ma soprattutto non vi obbliga ad avere un ControlState attivo per ogni controllo. Se ne deduce che si può addirittura disabilitare completamente il ViewState e poter contare sempre sulla persistenza delle variabili di un dato controllo.

Tutto questo è vero, ma solo in parte!

Allora vi starete chiedendo, ma se non è vero, perchè diavolo lo scrivi. Ho detto che non è vero solo in parte. Per poter funzionare, tanto ViewState che ControlState, devono abbracciare la tecnica del PostBack, cioè tramite una funzione Javascript iniettata dal framework nella pagina, i valori verranno ritrasmessi alla pagina stessa e riacquisiti per successive elaborazioni.

Supponiamo ora per un momento che – come nel mio caso – nella costruzione di un controllo avessi come limite il fatto di non dover usare funzioni Javascript (tralasciamo il perchè). Cosa succede? Niente Javascript = Niente PostBack. E allora?

Per ovviare a questo tipo di problema ho dovuto far ricorso ad un sistema alternativo di persistenza, basato sulla serializzazione dei miei dati direttamente in memoria tramite l’oggetto Session della pagina ASP.Net

La serializzazione e` il processo di conversione dello stato di un oggetto in un form che puo` essere mantenuto o trasportato.

Così facendo, con un paio di if all’interno del mio codice, e ricorrendo allo stesso flusso di esecuzione generato quando si usa il ControlState sono riuscito a persistere i valori del mio controllo senza far ricorso al Postback.

Di seguito mostro alcuni stralci di codice.

Per prima cosa occorre creare una classe che sia serializzabile, che serve tanto che vogliate usare il ControlState che questo sistema alternativo, quindi:


[Serializable]
internal struct PersistedData
{
public int test;
}

Occorre poi fare il controllo se si vuole usare il ControlState, e questo lo faremo nel metodo OnInit


if (PagingMode == PagingModeEnum.Postback)

Page.RegisterRequiresControlState(this);
else
LoadControlStateInSession();

Aggiungere la persistenza del metodo alternativo nel metodo PreRender. Non è necessaria quella del ControlState perchè li siete obbligati a fare – per far si che funzioni – un ovverride del metodo SaveControlState.


if (PagingMode != PagingModeEnum.Postback)
this.SaveControlStateInSession();

Infine incollare il codice relativo alle due funzioni di persistenza sopra utilizzate.


///
/// Saves state the specified storage mechanism by
/// first serializing to a string with the LosFormatter
///
private void SaveControlStateInSession()
{
LosFormatter output = new LosFormatter();
using (StringWriter writer = new StringWriter())
{
output.Serialize(writer, this.SaveControlState());
HttpContext.Current.Session[“__” + this.UniqueID] = writer.ToString();
}
}

///
/// Retrieves the serialized data from the Storage medium
/// as string using LosFormatter formatting.
///
private void LoadControlStateInSession()
{
string RawBuffer = HttpContext.Current.Session[“__” + this.UniqueID] as string;
if (RawBuffer == null)
return;

LosFormatter input = new LosFormatter();

this.LoadControlState(input.Deserialize(RawBuffer));
}

Le due funzioni si appoggiano alla classe LosFormatter, una classe nascosta nei meandri del System.Web.UI, utilizzata dal framework per serializzare il contenuto del ViewState nel famoso campo hidden __VIESTATE.

Nota del 20/01/2008: If you want to read the article in english, please follow the How to persist a control property without using PostBack link.