Durante lo sviluppo di applicazioni web ho avuto qualche volta la necessità di debuggare in Visual Studio.NET intercettando anche le eccezioni gestite poiché questa tecnica permette di intercettare eccezioni anche di altri threads. Per eccezioni gestite si intendono quelle scatenate all'interno di un costrutto try/catch.
Spesso però mi accadeva di dovermi sopportare decine di eccezioni non generate dal mio codice. La più frequente era un ArgumentException "Error binding to target name". Chiedendo a RafASM se questo capitava anche a lui e riflettendo con lui ho indagato e ho scoperto che questa eccezione proveniva da System.Web.UI.TemplateControl.GetDelegateInformation utilizzata a sua volta da HookUpAutomaticHandlers.
Aaaarghhhhh!!! Capito tutto. Questo metodo viene sfruttato per intercettare automaticamente a runtime eventi di usercontrol o di page sfruttando la sintassi Page_(Evento). Più dettagliamente per ogni evento tenta di creare un EventHandler tramite il metodo statico Delegate.CreateDelegate. Se non viene trovato un membro con lo stesso nome o con firma errata viene generate un'eccezione che verrà intercettata per effettuare un secondo tentativo di creazione delegate su un metodo con lo stesso nome ma mancante di parametri. Infatti, questa non la sapevo, possiamo intercettare l'evento Load con questa firma:
void Page_Load()
{ }
Tralasciando questo dettaglio, ci sarebbe da fare un ulteriore urlo perché questo doppio lavoro viene effettuato per altre 10 volte per gli altri vari eventi.
Sapendo che le istruzioni tra costrutti try sono più lente soprattutto se viene generata un eccezione (vi consiglio di leggere il libro di Marco) ho effettuato alcuni test.
Ponendo di avere una pagina con il metodo Page_Load ho creato l'handler racchiudendo la chiamata a CreateDelegate, per 500000 volte tra costrutti o senza, ecco i risultati:
Con try/catch: 7,391 s
Senza: 7,100 s
Ok, le iterazioni sono molte, anche spropositante ma più sono, più si nota la differenza. In fondo è poca e in linea con quanto detto prima. Ora provo la stessa pagina creando un delegate su un metodo che non esiste:
Con try/catch: 129,406! s
Senza: nessun risultato, l'eccezione non è gestita
Il degrado di performance è enorme!
Non è colpa di chi ha scritto il codice poiché non vi è altro modo. Per evitare l'eccezione si potrebbe tramite reflection cercare prima il membro, ma poi dovremmo riutilizzare CreateDelegate che effettuerà di nuovo una ricerca via reflection andando ad influire comunque sulle performance. Certo sarebbero migliori nel caso il metodo non esistesse ma inferiori se invece lo fosse. Forse era il caso far restituire null a CreateDelegate invece di generare un eccezione.
Probabilmente è stata fatta la scelta di pensare che se si usa l'AutoEventWireup i metodi da trovare esistono. Ma quante volte usiamo tutti e 10 gli eventi? Al massimo 3 o 4.
Sta di fatto che la l'AutoEventWireup è attiva di default per rendere meno indolore un primo approccio di un programmatore ad ASP.NET. Se usate VS.NET lo disattiva di default, ma ahime qualche volta creo controlli col notepad e me ne dimentico oppure utilizzo la funzione LoadControl.
Concludendo, io consiglio di non usarlo mai! Prendete il machine.config, andate alla sezione pages e impostate l'attributo autoEventWireup a false. Problema risolto :-D
Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.
- LINQ, lazy loading e architettura, l'11 marzo 2011 alle 18:42
- MetadataDiffViewer: aggiornato al .NET Framework 4.0, Silverlight 4.0 e Sharepoint 2010, il 7 gennaio 2010 alle 13:58
- .NET Framework 4.0 beta 1: Windows Communication Foundation, il 18 maggio 2009 alle 16:00
- Parallelizzare in Silverlight 2.0, il 21 aprile 2009 alle 00:25
- Silverlight: performance dell'isolated storage, il 16 aprile 2009 alle 17:38
- MetadataDiffViewer: differenze tra i framework, il 15 aprile 2009 alle 18:56