Alessio Pambianchi

ASP.NET AJAX ricerche-condivisione
posts - 21, comments - 43, trackbacks - 4

Piccola escursione su *HttpResponse.End()* & *ThreadAbortException*

E' chiaro che questo problema abbia avuto ben più importanti contributi, e ben più importanti oratori (visto il materiale "googleiano"), comunque essendomi trovato anche io in queste acque pantanose, vorrei dire la mia (scusatemi se è poco ;) ), anche in funzione di un *Post Pro Memoria*.

In questo ultimo periodo di lavoro mi sto occupando di un progetto Web abbastanza complesso che nel Front End fa un uso massivo di gridview. per migliorare la User Experience, è stato introdotto un controllo custom chiamato *YuiGrid* appartenente alla libreria ExtJs Extender Controls (codeplex), l'integrazione del controllo è stata abbastanza semplice, e *quasi* si stava per gioire, ma una controllata veloce ai log prodotti dall'aplpicazione evidenzia una serie di ThreadAbortException, generate ogni volta che sul controllo *YuiGrid* vengono premuti i bottoni first, prev, next, last naturalmente questi appartenenti alla logica della paginazione. Meglio ancora, le eccezioni vengono sollevate ogni volta che viene eseguito il metodo DataBind del controllo, che a sua volta è chiamato in corrispondenza degli eventi legati alla paginazione, e ancora più nel dettaglio l'eccezione viene sollevata solo dopo la prima load della pagina.

Analizzando il codice sorgente del controllo ho trovato le cause del problema:

//EnsureChildControls();
HttpResponse Response = HttpContext.Current.Response;
Response.Clear();
//Response.ContentType = "text";
//JavaScriptSerializer ser = new JavaScriptSerializer();
Response.Write("{\"records\":[" + parsedValue + "],\"totalCount\":\"" + this.TotalRecords + "\"}");
Response.End();

E' noto che la funzione *HttpResponse.End()* generi questo tipo di eccezione come documentato su MSDN, di conseguenza mi sono mosso per vedere come correggere l'errore, dopo alcuni test, ed un po di debug ecco la soluzione:

//EnsureChildControls();
HttpResponse Response = HttpContext.Current.Response;
Response.Clear();
//Response.ContentType = "text";
//JavaScriptSerializer ser = new JavaScriptSerializer();
Response.Write("{\"records\":[" + parsedValue + "],\"totalCount\":\"" + this.TotalRecords + "\"}");
//Response.End();
Response.Flush();
Response.Close();
return;

Naturalmente sono fortunato, ho a disposizione il codice sorgente del controllo, vorrei aggiungere anche che per lo stesso problema ho trovato differenti soluzioni ma non tutte lo risolvono, per cui come sempre provare provare provare.

Tags:

Print | posted on martedì 22 luglio 2008 11.01 | Filed Under [ ASP.NET AJAX ]

Feedback

Gravatar

# re: Piccola escursione su *HttpResponse.End()* & *ThreadAbortException*

Alessio,

forse non c'entra nulla, ma prova a leggere questo: http://blogs.msdn.com/johan/archive/2007/01/23/i-ve-upgraded-and-now-my-application-doesn-t-work-anymore.aspx

Fabrizio
22/07/2008 14.31 | Fabrizio
Gravatar

# re: Piccola escursione su *HttpResponse.End()* & *ThreadAbortException*

Alessio,
preciso meglio il mio commento di prima: ho paura che Flush + Close possa essere un problema su IIS7 (vista / win2008).
22/07/2008 14.41 | Fabrizio
Gravatar

# re: Piccola escursione su *HttpResponse.End()* & *ThreadAbortException*

Response.Write("Page.aspx",true);
22/07/2008 14.57 | alessio
Gravatar

# re: Piccola escursione su *HttpResponse.End()* & *ThreadAbortException*

Ciao Fabrizio,

Che dire, per testare le modifiche al codice sorgente del controllo custom *YuiGrid* utilizzo WindowsVista, VisualStudio 2008, l'applicazione viene testata non utilizzando il Visual Studio Development Server (cassini), ma utilizzando IIS 7.0. Poi pubblico la nuova .dll corretta nella pseudo produzione (Windows Server 2003 IIS 6) per eseguire test più approfonditi. Non so sono perplesso, dal post che mi hai girato sembra invece che le guidelines dicano il contrario mica male.
22/07/2008 15.06 | Alessio
Gravatar

# re: Piccola escursione su *HttpResponse.End()* & *ThreadAbortException*

Caio Fabrizio,

Per puro scrupolo, visto che mi hai messo la pulce all'orecchio, ho rieseguito un test sul custom control, quersta volta l'ho compilato targettando il FRMWRK 3.5, poi creato una nuova WebbApp sempre 3.5, verificato che il debug utilizzasse IIS 7.0, poi ho eseguito il deploy dell'applicazione in una virtualdirectory creata in ISS 7.0 ho testato il tutto, varie volte ma funziona. Nessuna eccezione viene solevata e sembra funzionare tutto correttamente.
22/07/2008 16.14 | Alessio
Gravatar

# re: Piccola escursione su *HttpResponse.End()* & *ThreadAbortException*

Ciao Alessio,

non saprei. Quando ho letto il tuo post mi è venuta in mente quella cosa su IIS7 e Response.end/close/flush. E ho pensato di segnalartela.
Per come l'ho capita io, il Close su IIS7 chiude il socket come su II6. Ma flush si comporta in modo diverso: su iis6 manda al client mentre su iis7 manda ad un buffer intermedio. Bisognerebbe fare un prova con un connessione lenta, in modo che nel buffer ci sia ancora qualcosa e poi dare un Close. E vedere cosa succede.
I test che hai fatto, immagino li abbia fatti in LAN, vero ?
22/07/2008 17.52 | Fabrizio
Gravatar

# re: Piccola escursione su *HttpResponse.End()* & *ThreadAbortException*

Ciao Fabrizio,

Ho capito la tua eccezione, probabile che in caso di intasamento della rete, alcune informazioni rimangano nel buffer intermedio e vengano troncate alla close (spiacevole).

Per quanto riguarda il supporto fisico, non hai sbagliato tutti i test vengono eseguiti in un ambiente collegato tramite LAN, per cui potremmo dire una situazione ideale (sbagliatissimo ma è così).

Comunque in produzione la situazione non è tanto diversa si tratta infatti di un sistema di Applicazioni Web dedicato a girare su di una intranet aziendale.

La gestione dei LOG mi impone (paletto) che anche queste eccezioni vengano segnalate, ora se a ogni click viene genera l'eccezione e considerato un numero di utilizzatori medi dell'applicazione nell'ordine delle centinaia, servirebbero un sacco di risorse per la gestione dei log che invece devono mantenere il loro stile essenziale ma efficace.

Ultima considerazione, personalmente non ho nulla in contrario nell'utilizzo di *End()* al posto di *Flush()* & *Close()*. l'unico problema è che l'eccezione sollevata nell'utilizzo della *End()* non è gestibile, anche se metto il codice del *DataBind()* all'interno di un blocco try catch essa si propaga comunque fino al gestore dei LOG.
23/07/2008 9.21 | Alessio
Gravatar

# re: Piccola escursione su *HttpResponse.End()* & *ThreadAbortException*

Alessio,

il fatto che un ThreadAbortException non la riesci a "fermare" è by-design (spero di non dire scemenze).
Vedi MSDN: http://msdn.microsoft.com/en-us/library/system.threading.threadabortexception.aspx
Remarks: When a call is made to the Abort method to destroy a thread, the common language runtime throws a ThreadAbortException. ThreadAbortException is a special exception that can be caught, but it will automatically be raised again at the end of the catch block.

Se vuoi indagare un po', prova a leggerti questo, ci sono un po' di spunti interessanti:
http://www.west-wind.com/WebLog/posts/368975.aspx

Un paio ancora di cose velocissime:
- personalmente uso Response.End ma la metto sempre "al fondo", niente codice dopo.
- trovo un po' singolare che un componente (YiuGrid) faccia una chiamata a Response.End... boh....

ciao

23/07/2008 11.54 | Fabrizio
Gravatar

# re: Piccola escursione su *HttpResponse.End()* & *ThreadAbortException*

Ciao Fabrizio,

si in effetti il tuo spunto è interessante, ho cercato di verificare la compatibilità delle varie soluzioni proposte (http://www.west-wind.com/WebLog/posts/368975.aspx), con l'user control *YuiGrid* ed in particolare ho trovato interessante l'utilizzo della funzione:

HttpContext.Current.ApplicationInstance.CompleteRequest();

al posto della funzione

HttpContext.Current.Response.Close();

per info: http://msdn.microsoft.com/en-us/library/system.web.httpapplication.completerequest.aspx.

Purtroppo anche questa soluzione non da esito positivo in quanto sostituendola alla Close(); poi non vengono aggiornati i dati appartenenti all'User Control.
23/07/2008 14.12 | Alessio
Gravatar

# re: Piccola escursione su *HttpResponse.End()* & *ThreadAbortException*

Dimenticavo, la soluzione viene comunque consigliata da Microsoft: http://support.microsoft.com/kb/312629#appliesto dove viene esplicitamente detto di usare la HttpContext.Current.ApplicationInstance.CompleteRequest(); al posto di HttpContext.Current.Response.End();

Ciao, grazie per gli approfondimenti.
23/07/2008 14.19 | Alessio
Gravatar

# re: Piccola escursione su *HttpResponse.End()* & *ThreadAbortException*

Alla fine comunque potremmo utilizzare benissimo HttpResponse.End() basta utilizzare un gestore delle eccezioni di questo tipo.

Catch ex As Exception
If Not (TypeOf ex Is System.Threading.ThreadAbortException) Then
'menage exception
End If
End Try

riusciamo a beccare tutte le eccezioni al di fuori delle ThreadAbortException.

NB. non ho verificato se il codice sopra possa comportare problemi aggiuntivi, qualsiasi commento è gradito.
28/08/2008 11.50 | Alessio

Post Comment

Title  
Name  
Email
Url
Comment   
Please add 3 and 5 and type the answer here:

Powered by: