How to persist a control property without using PostBack

For whom program in ASP.Net, since the first version you probably start to appreciate and contemporary hate the page’s StateBag, otherwise called ViewState. Without going through the particulars, to avoid loosing the article path, in few words the ViewState take care to serialize the content of the page variables into a string that is passed back to the next page request through a mechanism called PostBack.
The drama is that not all controls need ViewState, and often this persisting process is turned off to reserve memory and avoid unuseful server roundtrip.

Things changed when ASP.Net 2.0 framework has been released: a new method called ControlState was introduced for persistance. This method basically works as the ViewState, but first of all cannot be deactivated by the web page programmer, and it memorize only what is really needed (according to the override you will do in your code). Again, you can also decide for which control activate this repository and for which not.
Immediately should jumps in mind that you can even completely deactivate the ViewState and continue to be supported by the Control’s variable persistance without any matter.

That’s all true, but only in part!

So you are probably asking why I’m writing this if this isn’t the truth. As I said, it’s not true only in part. To correctly work, both ViewState and ControlState needs to embrace the PostBack technique. For whom don’t know what PostBack is, it’s a small javascript function automatically added by the framework to the rendered HTML page that take care to collect every input control’s value and to submit them to the same page through a server call. This let you restore value on the next page load for following elaboration.

Now, suppose just for a moment – as it was in my case – while I was developing a control to have a limit where you cannot use Javascript (without worrying why). What happen in this case? No javavascript = no PostBack. And then?

To avoid this kind of problem I had to use an alternative way to persist my control’s value, based always on the serialization, but persisting values in the Session object.

The serialization is the process of saving an object into a storage medium (such as a file or a memory buffer) and to transmit it across a network request.

In this way, with a couple of if inside the code, and using the same execution path used by the ControlState, I finally successfull persisted my control’s value without using PostBack.

Below an abstract of the code I used.

First of all I created a serializable class that you need both you want to persist values in a traditional way and with Session method.

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

You then add a condition if you want to use the ControlState mechanism or not. This can be done in the OnInit method of our control.

if (PagingMode == PagingModeEnum.Postback)
Page.RegisterRequiresControlState(this);
else
LoadControlStateInSession();

It’s now necessary to add the alternative storage path in the PreRender override. You shouldn’t do anything for the ControlState since you are obliged to override the SaveControlState method.

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

Finally paste the code that will perform the persistance above used.

///

/// 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));
}

The above function use the LosFormatter class that is an hidden class of the System.Web.UI namespace, used by the framework for the serialization process of the page ViewState and of the famous hidden form field __VIESTATE.

Intercettare il PostBack di un controllo lato client

L’uso del PostBack in una pagina ASP.Net consente di inviare al server – attraverso la stessa pagina – un evento che indica che qualcosa è accaduto nella pagina stessa.
Questo meccanismo avviene tramite una funziona javascript che il framework aggiunge all’HTML della pagina generata e renderizzata nel browser e alla quale associa “il click” dei controlli server per i quali si vuole trasmettere informazioni al server affinchè quest’ultimo le processi.

Fintanto che questo meccanismo viene fatto attraverso controlli lato server, tutto funziona “magicamente” con del codice testato dal team di sviluppo di ASP.Net.

Quando però, per qualche ragione che non sto a sindacare, è necessario che a fare il postback sia un controllo lato client, bisogna fare in modo che il controllo client si agganci al meccanismo di PostBack e lato server se ne intercetti l’evento.

Come controllare il postback lato client?

A partire dalla versione 2.0 del framework è stato introdotto il metodo GetPostBackEventReference per la classe ClientScriptManager, che automaticamente genera quasi tutto il codice necessario per fare in modo che questo processo funzioni correttamente.

Si supponga per esempio che si vuole generare un link standard che faccia il PostBack. Potremmo scrivere qualcosa di questo tipo:

String.Format("Test", csm.GetPostBackEventReference(NomeDelControllo, ValoreDelPostBack));

Prendendo il risultato del Format e reindirizzandolo verso il corretto output.

Ovviamente dovremo prima creare un oggetto di tipo ClientScriptManager, che nel mio caso è csm, al quale passeremo un reference del codice javascript contenuto nella pagina con una sintassi come questa:

ClientScriptManager csm = Page.ClientScript;

Fatto questo, sarà possibile, premento sul link, intercettare il PostBack nella successiva chiamata alla pagina, nell’ormai noto evento OnLoad, con qualcosa di questo tipo:

if (Page.IsPostBack)
{
if (Page.Request.Form["__EVENTTARGET"] != "...."){
if (Page.Request.Form["__EVENTARGUMENT"] != string.Empty){
....
}
}
]

Technorati Tags: