Stavo appronfondendo le funzioni del cosidetto "Web 2.0" introdotte nel fx 2.0 (ICallbackEventHandler, GetCallbackEventReference) e in particolare mi sono focalizzato sul problema relativo al ripristino dello stato dei controlli in seguito alla callback. Dopo qualche analisi del tracciato HTTP delle richieste delle chiamate effettuate dalle callback ci si accorge che vengono postati i dati dei controlli dei form... ma vengono postati dati vecchi.
Alla ricerca dell'origine del problema mi sono spinto all'analisi degli script contenuti in "WebResource.axd" (contenuto virtuale). La lettura "WebResource.axd" è molto interessante... la consiglio a tutti perchè fa capire come un buon/geniale utilizzo di tecnologia da tempo esistente ha fatto nascere il concetto di callback che è identificato come innovazione degli ultimi tempi! ;-p Gli script "js" e i concetti possono essere portati anche in linguaggi/tecnologie web not "ASP.NET 2.0".
Analizzando gli script ci si accorge che il problema è che i dati che vengono inviati, eccezion fatta per un argument definito nella costruzione della funzione di callback stessa, sono una fotografia dei dati contenuti nei controlli al momento dell'ultimo caricamento della pagina... Non sono un subset dei dati contenuti nella webform ma sono proprio una fototagrafia vecchia degli stessi.
Per far si che a seguito della callback venga inviato lo stato in essere dei controlli occorre registrare qualche riga di codice javascript prima di invocare la funzione di callback.
__theFormPostCollection = new Array();
__theFormPostData = '';
WebForm_InitCallback();
Ho poi trovato conferma della soluzione in "Custom Script Callbacks in ASP.NET" di Dino Esposito.
Ho fatto un check su Lady Bug dove ho trovato "ASP.NET should provide a way to execute a client callback with up-to-date form post data" a cui MS dopo il consueto ringraziamento per il suggerimento ha risposto "Callbacks are not posts, the form data therefore returned, is the state of the page when first loaded. If you want to pass updated values to a callback, include them in the callback arguments." Risposta che mi sembra DiComodo, Politica e un poco Ideoligica.
La cosa non mi piace. Ho quindi risposto - a modo mio - con "ASP.NET should provide a way to execute a client callback with up-to-date form post data (2)". Il problema è che l'esigenza ci sia effettivamente ed è troppo limitato l'uso del solo argument per postare lo stato completo della form. Credo che avere come opzione la possibilità di avere l'effettivo stato della form completa sia una cosa interessante e che sopratutto eviterà di far si che la gente prenda il vizio di scrivere il codice non documentato per il risolvere il problema saltando il "ClientScriptManager" :( Non solo ma dire di usare il solo argument per postare lo stato dei controlli che ci interessano farebbe introdurre join e split di stringhe tanto complessi quanto complesso è lo stato del controllo che si vuole riportare... e il che renderebbe tanto più poco leggibile e fludio il codice.
Nella speranza che il suggerimento venga accolto - o cmq di ricevere risposta che mi piaccia di più - ho iniziato a implementare una classe di utilità per wrappare il problema...
public static class ClientScriptManagerHelper
{
private static readonly string WEBFORM_NEWINITIALIZECALLBACK = Guid.NewGuid().ToString();
public static string GetNewInitializeCallbackReference()
{
return "WebForm_NewInitCallback()";
}
public static void RegisterNewInitializeCallback(Type type, ClientScriptManager cm)
{
if (!cm.IsClientScriptBlockRegistered(WEBFORM_NEWINITIALIZECALLBACK))
{
cm.RegisterClientScriptBlock(type, WEBFORM_NEWINITIALIZECALLBACK,
@"
function WebForm_NewInitCallback()
{
__theFormPostCollection = new Array();
__theFormPostData = '';
WebForm_InitCallback();
}
", true);
}
}
}
... e questo un esempio di utilizzo.
...
if (!IsCallback)
{
ClientScriptManagerHelper.RegisterNewInitializeCallback(GetType(), cm);
cm.RegisterClientScriptBlock(GetType(), "readSelectedKeyValues_byCallback",
@"
function readSelectedKeyValues_RaiseCallbackEvent()
{
" + ClientScriptManagerHelper.GetNewInitializeCallbackReference() + @";
var arg = '';
" + cm.GetCallbackEventReference(this, "arg", "readSelectedKeyValues_GetCallbackResult", string.Empty) + @";
}
function readSelectedKeyValues_GetCallbackResult(arg, context)
{
alert(arg);
}
", true);
}
...
posted @ domenica 7 gennaio 2007 16:00