Elaborazione delle eccezioni non gestite (C#)
Visualizzare o scaricare il codice di esempio (procedura per il download)
Quando si verifica un errore di runtime in un'applicazione Web nell'ambiente di produzione, è importante notificare a uno sviluppatore e registrare l'errore in modo che possa essere diagnosticato in un secondo momento. Questa esercitazione offre una panoramica del modo in cui ASP.NET elabora gli errori di runtime ed esamina un modo per eseguire codice personalizzato ogni volta che un'eccezione non gestita si verifica fino al runtime di ASP.NET.
Introduzione
Quando si verifica un'eccezione non gestita in un'applicazione ASP.NET, viene visualizzata una bolla fino al runtime di ASP.NET, che genera l'evento Error
e visualizza la pagina di errore appropriata. Esistono tre diversi tipi di pagine di errore: l'errore di runtime Schermata gialla di morte (YSOD); i dettagli dell'eccezione YSOD; e pagine di errore personalizzate. Nell'esercitazione precedente è stata configurata l'applicazione in modo da usare una pagina di errore personalizzata per gli utenti remoti e i dettagli dell'eccezione YSOD per gli utenti che visitano localmente.
L'uso di una pagina di errore personalizzata descrittiva che corrisponde all'aspetto del sito è preferibile all'impostazione predefinita Errore di runtime YSOD, ma la visualizzazione di una pagina di errore personalizzata è solo una parte di una soluzione completa di gestione degli errori. Quando si verifica un errore in un'applicazione nell'ambiente di produzione, è importante che gli sviluppatori ricevono una notifica dell'errore in modo che possano scoprire la causa dell'eccezione e risolverla. Inoltre, i dettagli dell'errore devono essere registrati in modo che l'errore possa essere esaminato e diagnosticato in un secondo momento.
Questa esercitazione illustra come accedere ai dettagli di un'eccezione non gestita in modo che possano essere registrati e notificati dallo sviluppatore. Le due esercitazioni successive a questa esplorano le librerie di registrazione degli errori che, dopo un po' di configurazione, in modo da notificare automaticamente agli sviluppatori errori di runtime e registrare i relativi dettagli.
Nota
Le informazioni esaminate in questa esercitazione sono più utili se è necessario elaborare eccezioni non gestite in modo univoco o personalizzato. Nei casi in cui è sufficiente registrare l'eccezione e inviare una notifica a uno sviluppatore, l'uso di una libreria di registrazione degli errori è il modo per procedere. Le due esercitazioni successive offrono una panoramica di due librerie di questo tipo.
Esecuzione di codice quando viene generato l'eventoError
Gli eventi forniscono un meccanismo per segnalare che si è verificato qualcosa di interessante e per consentire a un altro oggetto di eseguire il codice in risposta. Gli sviluppatori ASP.NET sono abituati a pensare in termini di eventi. Se si vuole eseguire codice quando il visitatore fa clic su un determinato pulsante, si crea un gestore eventi per l'evento di Click
Button e si inserisce il codice. Dato che il runtime ASP.NET genera l'evento Error
ogni volta che si verifica un'eccezione non gestita, è necessario che il codice per la registrazione dei dettagli dell'errore venga inserito in un gestore eventi. Ma come si crea un gestore eventi per l'evento Error
?
L'evento Error
è uno di molti eventi nella HttpApplication
classe che vengono generati in determinate fasi della pipeline HTTP durante la durata di una richiesta. Ad esempio, l'evento HttpApplication
della classe viene generato all'inizio di ogni richiesta. Il relativo AuthenticateRequest
evento viene generato quando un modulo di BeginRequest
sicurezza ha identificato il richiedente. Questi HttpApplication
eventi consentono allo sviluppatore di pagine di eseguire la logica personalizzata nei vari punti della durata di una richiesta.
I gestori eventi per gli HttpApplication
eventi possono essere inseriti in un file speciale denominato Global.asax
. Per creare questo file nel sito Web, aggiungere un nuovo elemento alla radice del sito Web usando il modello Global Application Class con il nome Global.asax
.
Figura 1: Aggiungere Global.asax
all'applicazione Web
(Fare clic per visualizzare l'immagine a dimensione intera)
Il contenuto e la struttura del Global.asax
file creato da Visual Studio differiscono leggermente in base al fatto che si usi un progetto applicazione Web (WAP) o un progetto di sito Web (WSP). Con un WAP, Global.asax
viene implementato come due file separati, Global.asax
e Global.asax.cs
. Il file non contiene altro che una @Application
direttiva che fa riferimento al .cs
file. I Global.asax
gestori eventi di interesse vengono definiti nel Global.asax.cs
file. Per i provider di servizi di configurazione, viene creato solo un singolo file e Global.asax
i gestori eventi vengono definiti in un <script runat="server">
blocco.
Il Global.asax
file creato in un WAP dal modello Classe di applicazione globale di Visual Studio include gestori eventi denominati Application_BeginRequest
, Application_AuthenticateRequest
e Application_Error
, che sono gestori eventi rispettivamente per gli HttpApplication
eventi BeginRequest
, AuthenticateRequest
e Error
. Sono inoltre disponibili gestori eventi denominati Application_Start
, Session_Start
, Application_End
e Session_End
, che sono gestori eventi che vengono attivati all'avvio dell'applicazione Web, all'avvio di una nuova sessione, al termine dell'applicazione e alla fine di una sessione, rispettivamente. Il Global.asax
file creato in un WSP da Visual Studio contiene solo i Application_Error
gestori eventi , , Application_End
Application_Start
Session_Start
, e Session_End
.
Nota
Quando si distribuisce l'applicazione ASP.NET è necessario copiare il Global.asax
file nell'ambiente di produzione. Il Global.asax.cs
file, creato nel WAP, non deve essere copiato nell'ambiente di produzione perché questo codice viene compilato nell'assembly del progetto.
I gestori eventi creati dal modello Global Application Class di Visual Studio non sono esaustivi. È possibile aggiungere un gestore eventi per qualsiasi HttpApplication
evento assegnando un nome al gestore eventi Application_EventName
. Ad esempio, è possibile aggiungere il codice seguente al Global.asax
file per creare un gestore eventi per l'eventoAuthorizeRequest
:
protected void Application_AuthorizeRequest(object sender, EventArgs e)
{
// Event handler code
}
Analogamente, è possibile rimuovere tutti i gestori eventi creati dal modello classe applicazione globale non necessari. Per questa esercitazione è necessario solo un gestore eventi per l'evento Error
. Rimuovere gli altri gestori eventi dal Global.asax
file.
Nota
I moduli HTTP offrono un altro modo per definire i gestori eventi per HttpApplication
gli eventi. I moduli HTTP vengono creati come file di classe che possono essere inseriti direttamente all'interno del progetto dell'applicazione Web o separati in una libreria di classi separata. Poiché possono essere separati in una libreria di classi, i moduli HTTP offrono un modello più flessibile e riutilizzabile per la creazione HttpApplication
di gestori eventi. Mentre il Global.asax
file è specifico dell'applicazione Web in cui si trova, i moduli HTTP possono essere compilati in assembly, a questo punto l'aggiunta del modulo HTTP a un sito Web è semplice come eliminare l'assembly nella Bin
cartella e registrare il modulo in Web.config
. Questa esercitazione non esamina la creazione e l'uso di moduli HTTP, ma le due librerie di registrazione degli errori usate nelle due esercitazioni seguenti vengono implementate come moduli HTTP. Per altre informazioni sui vantaggi dei moduli HTTP, vedere Uso di moduli HTTP e gestori per creare componenti pluggable ASP.NET.
Recupero di informazioni sull'eccezione non gestita
A questo punto è disponibile un file Global.asax con un Application_Error
gestore eventi. Quando questo gestore eventi viene eseguito, è necessario inviare una notifica a uno sviluppatore dell'errore e registrarne i dettagli. Per eseguire queste attività, è prima necessario determinare i dettagli dell'eccezione generata. Utilizzare il metodo dell'oggetto GetLastError
Server per recuperare i dettagli dell'eccezione non gestita che ha causato la generazione dell'eventoError
.
protected void Application_Error(object sender, EventArgs e)
{
// Get the error details
HttpException lastErrorWrapper =
Server.GetLastError() as HttpException;
}
Il GetLastError
metodo restituisce un oggetto di tipo Exception
, che è il tipo di base per tutte le eccezioni in .NET Framework. Tuttavia, nel codice precedente si esegue il cast dell'oggetto Exception restituito da GetLastError
in un HttpException
oggetto . Se l'evento Error
viene generato perché è stata generata un'eccezione durante l'elaborazione di una risorsa ASP.NET, l'eccezione generata viene sottoposta a wrapping all'interno di un oggetto HttpException
. Per ottenere l'eccezione effettiva che ha precipitato l'evento Error, utilizzare la InnerException
proprietà . Se l'evento Error
è stato generato a causa di un'eccezione basata su HTTP, ad esempio una richiesta per una pagina inesistente, viene generata un'eccezione HttpException
, ma non ha un'eccezione interna.
Il codice seguente usa per GetLastErrormessage
recuperare informazioni sull'eccezione che ha attivato l'evento Error
, archiviando in HttpException
una variabile denominata lastErrorWrapper
. Archivia quindi il tipo, il messaggio e l'analisi dello stack dell'eccezione di origine in tre variabili stringa, verificando se lastErrorWrapper
è l'eccezione effettiva che ha attivato l'evento Error
(nel caso di eccezioni basate su HTTP) o se si tratta semplicemente di un wrapper per un'eccezione generata durante l'elaborazione della richiesta.
protected void Application_Error(object sender, EventArgs e)
{
// Get the error details
HttpException lastErrorWrapper =
Server.GetLastError() as HttpException;
Exception lastError = lastErrorWrapper;
if (lastErrorWrapper.InnerException != null)
lastError = lastErrorWrapper.InnerException;
string lastErrorTypeName = lastError.GetType().ToString();
string lastErrorMessage = lastError.Message;
string lastErrorStackTrace = lastError.StackTrace;
}
A questo punto sono disponibili tutte le informazioni necessarie per scrivere codice che scriva i dettagli dell'eccezione in una tabella di database. È possibile creare una tabella di database con colonne per ognuno dei dettagli dell'errore di interesse, ovvero il tipo, il messaggio, l'analisi dello stack e così via, insieme ad altre informazioni utili, ad esempio l'URL della pagina richiesta e il nome dell'utente attualmente connesso. Application_Error
Nel gestore eventi ci si connetterà quindi al database e si inserisce un record nella tabella. Analogamente, è possibile aggiungere codice per avvisare uno sviluppatore dell'errore tramite posta elettronica.
Le librerie di registrazione degli errori esaminate nelle due esercitazioni successive forniscono tali funzionalità predefinite, quindi non è necessario compilare questa registrazione e notifica degli errori manualmente. Tuttavia, per illustrare che l'evento Error
viene generato e che il Application_Error
gestore eventi può essere usato per registrare i dettagli degli errori e inviare una notifica a uno sviluppatore, aggiungere codice che notifica a uno sviluppatore quando si verifica un errore.
Notifica a uno sviluppatore quando si verifica un'eccezione non gestita
Quando si verifica un'eccezione non gestita nell'ambiente di produzione, è importante avvisare il team di sviluppo in modo che possa valutare l'errore e determinare quali azioni è necessario eseguire. Ad esempio, se si verifica un errore durante la connessione al database, sarà necessario controllare il stringa di connessione e, ad esempio, aprire un ticket di supporto con la società di hosting Web. Se l'eccezione si è verificata a causa di un errore di programmazione, potrebbe essere necessario aggiungere codice aggiuntivo o logica di convalida per evitare tali errori in futuro.
Le classi .NET Framework nello spazio dei nomi semplificano l'invio System.Net.Mail
di un messaggio di posta elettronica. La classe rappresenta un messaggio di posta elettronica e ha proprietà come To
, Subject
From
, Body
, e Attachments
.MailMessage
Viene SmtpClass
utilizzato per inviare un oggetto utilizzando un MailMessage
server SMTP specificato. Le impostazioni del server SMTP possono essere specificate a livello di codice o dichiarativo nell'elemento <system.net>
in .Web.config file
Per altre informazioni sull'invio di messaggi di posta elettronica in un'applicazione ASP.NET, vedere l'articolo Invio di posta elettronica da un sito Pagine Web ASP.NET e System.Net.Mail.
Nota
L'elemento <system.net>
contiene le impostazioni del server SMTP utilizzate dalla classe durante l'invio SmtpClient
di un messaggio di posta elettronica. La società di hosting Web ha probabilmente un server SMTP che è possibile usare per inviare messaggi di posta elettronica dall'applicazione. Per informazioni sulle impostazioni del server SMTP da usare nell'applicazione Web, vedere la sezione relativa al supporto dell'host Web.
Aggiungere il codice seguente al Application_Error
gestore eventi per inviare uno sviluppatore a un messaggio di posta elettronica quando si verifica un errore:
void Application_Error(object sender, EventArgs e)
{
// Get the error details
HttpException lastErrorWrapper =
Server.GetLastError() as HttpException;
Exception lastError = lastErrorWrapper;
if (lastErrorWrapper.InnerException != null)
lastError = lastErrorWrapper.InnerException;
string lastErrorTypeName = lastError.GetType().ToString();
string lastErrorMessage = lastError.Message;
string lastErrorStackTrace = lastError.StackTrace;
const string ToAddress = "support@example.com";
const string FromAddress = "support@example.com";
const string Subject = "An Error Has Occurred!";
// Create the MailMessage object
MailMessage mm = new MailMessage(FromAddress, ToAddress);
mm.Subject = Subject;
mm.IsBodyHtml = true;
mm.Priority = MailPriority.High;
mm.Body = string.Format(@"
<html>
<body>
<h1>An Error Has Occurred!</h1>
<table cellpadding=""5"" cellspacing=""0"" border=""1"">
<tr>
<tdtext-align: right;font-weight: bold"">URL:</td>
<td>{0}</td>
</tr>
<tr>
<tdtext-align: right;font-weight: bold"">User:</td>
<td>{1}</td>
</tr>
<tr>
<tdtext-align: right;font-weight: bold"">Exception Type:</td>
<td>{2}</td>
</tr>
<tr>
<tdtext-align: right;font-weight: bold"">Message:</td>
<td>{3}</td>
</tr>
<tr>
<tdtext-align: right;font-weight: bold"">Stack Trace:</td>
<td>{4}</td>
</tr>
</table>
</body>
</html>",
Request.RawUrl,
User.Identity.Name,
lastErrorTypeName,
lastErrorMessage,
lastErrorStackTrace.Replace(Environment.NewLine, "<br />"));
// Attach the Yellow Screen of Death for this error
string YSODmarkup = lastErrorWrapper.GetHtmlErrorMessage();
if (!string.IsNullOrEmpty(YSODmarkup))
{
Attachment YSOD =
Attachment.CreateAttachmentFromString(YSODmarkup, "YSOD.htm");
mm.Attachments.Add(YSOD);
}
// Send the email
SmtpClient smtp = new SmtpClient();
smtp.Send(mm);
}
Mentre il codice precedente è piuttosto lungo, la maggior parte di esso crea il codice HTML visualizzato nel messaggio di posta elettronica inviato allo sviluppatore. Il codice inizia facendo riferimento all'oggetto HttpException
restituito dal GetLastError
metodo (lastErrorWrapper
). L'eccezione effettiva generata dalla richiesta viene recuperata tramite lastErrorWrapper.InnerException
e viene assegnata alla variabile lastError
. Le informazioni di tipo, messaggio e analisi dello stack vengono recuperate da lastError
e archiviate in tre variabili stringa.
Viene quindi creato un MailMessage
oggetto denominato mm
. Il corpo del messaggio di posta elettronica è formattato in formato HTML e visualizza l'URL della pagina richiesta, il nome dell'utente attualmente connesso e le informazioni sull'eccezione (tipo, messaggio e analisi dello stack). Uno degli aspetti interessanti della HttpException
classe consiste nel fatto che è possibile generare il codice HTML usato per creare la schermata gialla della morte (YSOD) dei dettagli dell'eccezione chiamando il metodo GetHtmlErrorMessage. Questo metodo viene usato qui per recuperare il markup YSOD dettagli eccezione e aggiungerlo al messaggio di posta elettronica come allegato. Una parola di attenzione: se l'eccezione che ha attivato l'evento Error
è stata un'eccezione basata su HTTP (ad esempio una richiesta di una pagina inesistente), il GetHtmlErrorMessage
metodo restituirà null
.
Il passaggio finale consiste nell'inviare .MailMessage
Questa operazione viene eseguita creando un nuovo SmtpClient
metodo e chiamando il relativo Send
metodo.
Nota
Prima di usare questo codice nell'applicazione Web, è necessario modificare i valori nelle ToAddress
costanti e FromAddress
da support@example.com a qualsiasi indirizzo di posta elettronica da cui deve essere inviato e originato il messaggio di posta elettronica di notifica degli errori. Sarà anche necessario specificare le impostazioni del server SMTP nella <system.net>
sezione in Web.config
. Consultare il provider host Web per determinare le impostazioni del server SMTP da usare.
Con questo codice sul posto ogni volta che si verifica un errore, lo sviluppatore invia un messaggio di posta elettronica che riepiloga l'errore e include YSOD. Nell'esercitazione precedente è stato illustrato un errore di runtime visitando Genre.aspx e passando un valore non valido ID
tramite la stringa di query, ad esempio Genre.aspx?ID=foo
. Visitando la pagina con il Global.asax
file sul posto si produce la stessa esperienza utente dell'esercitazione precedente: nell'ambiente di sviluppo si continuerà a visualizzare la schermata gialla della morte dei dettagli dell'eccezione, mentre nell'ambiente di produzione verrà visualizzata la pagina di errore personalizzata. Oltre a questo comportamento esistente, lo sviluppatore invia un messaggio di posta elettronica.
La figura 2 mostra il messaggio di posta elettronica ricevuto quando si visita Genre.aspx?ID=foo
. Il corpo del messaggio di posta elettronica riepiloga le informazioni sull'eccezione, mentre l'allegato YSOD.htm
visualizza il contenuto visualizzato in Dettagli eccezione YSOD (vedere la figura 3).
Figura 2: Lo sviluppatore invia una notifica tramite posta elettronica ogni volta che si verifica un'eccezione non gestita
(Fare clic per visualizzare l'immagine a dimensione intera)
Figura 3: La notifica tramite posta elettronica include i dettagli dell'eccezione YSOD come allegato
(Fare clic per visualizzare l'immagine a dimensione intera)
Informazioni sull'uso della pagina di errore personalizzata?
Questa esercitazione ha illustrato come usare Global.asax
e il Application_Error
gestore eventi per eseguire il codice quando si verifica un'eccezione non gestita. In particolare, questo gestore eventi è stato usato per notificare a uno sviluppatore un errore; È possibile estenderlo anche per registrare i dettagli dell'errore in un database. La presenza del Application_Error
gestore eventi non influisce sull'esperienza dell'utente finale. Viene comunque visualizzata la pagina di errore configurata, ad esempio dettagli errore YSOD, errore di runtime YSOD o pagina di errore personalizzata.
È naturale chiedersi se il file e Application_Error
l'evento Global.asax
sono necessari quando si usa una pagina di errore personalizzata. Quando si verifica un errore, l'utente visualizza la pagina di errore personalizzata, quindi perché non è possibile inserire il codice per notificare allo sviluppatore e registrare i dettagli dell'errore nella classe code-behind della pagina di errore personalizzata? Anche se è certamente possibile aggiungere codice alla classe code-behind della pagina di errore personalizzata, non si ha accesso ai dettagli dell'eccezione che ha attivato l'evento Error
quando si usa la tecnica esaminata nell'esercitazione precedente. La chiamata al GetLastError
metodo dalla pagina di errore personalizzata restituisce Nothing
.
Il motivo di questo comportamento è dovuto al raggiungimento della pagina di errore personalizzata tramite un reindirizzamento. Quando un'eccezione non gestita raggiunge il runtime di ASP.NET il motore di ASP.NET genera il relativo Error
evento (che esegue il gestore eventi) e quindi reindirizza l'utente Application_Error
alla pagina di errore personalizzata eseguendo un oggetto Response.Redirect(customErrorPageUrl)
. Il Response.Redirect
metodo invia una risposta al client con un codice di stato HTTP 302, indicando al browser di richiedere un nuovo URL, ovvero la pagina di errore personalizzata. Il browser richiede quindi automaticamente questa nuova pagina. È possibile indicare che la pagina di errore personalizzata è stata richiesta separatamente dalla pagina in cui è stato generato l'errore perché la barra degli indirizzi del browser cambia nell'URL della pagina di errore personalizzata (vedere la figura 4).
Figura 4: Quando si verifica un errore, il browser viene reindirizzato all'URL della pagina degli errori personalizzata
(Fare clic per visualizzare l'immagine a dimensione intera)
L'effetto netto è che la richiesta in cui si è verificata l'eccezione non gestita termina quando il server risponde con il reindirizzamento HTTP 302. La richiesta successiva alla pagina di errore personalizzata è una nuova richiesta; da questo punto il motore di ASP.NET ha eliminato le informazioni sull'errore e, inoltre, non ha modo di associare l'eccezione non gestita nella richiesta precedente alla nuova richiesta per la pagina di errore personalizzata. Questo è il motivo per cui GetLastError
restituisce null
quando viene chiamato dalla pagina di errore personalizzata.
Tuttavia, è possibile che la pagina di errore personalizzata venga eseguita durante la stessa richiesta che ha causato l'errore. Il Server.Transfer(url)
metodo trasferisce l'esecuzione all'URL specificato ed elabora l'esecuzione all'interno della stessa richiesta. È possibile spostare il codice nel Application_Error
gestore eventi nella classe code-behind della pagina di errore personalizzata, sostituendolo con Global.asax
il codice seguente:
protected void Application_Error(object sender, EventArgs e)
{
// Transfer the user to the appropriate custom error page
HttpException lastErrorWrapper =
Server.GetLastError() as HttpException;
if (lastErrorWrapper.GetHttpCode() == 404)
{
Server.Transfer("~/ErrorPages/404.aspx");
}
else
{
Server.Transfer("~/ErrorPages/Oops.aspx");
}
}
Ora quando si verifica un'eccezione non gestita, il gestore eventi trasferisce il Application_Error
controllo alla pagina di errore personalizzata appropriata in base al codice di stato HTTP. Poiché il controllo è stato trasferito, la pagina di errore personalizzata ha accesso alle informazioni sulle eccezioni non gestite tramite Server.GetLastError
e può inviare una notifica a uno sviluppatore dell'errore e registrarne i dettagli. La Server.Transfer
chiamata impedisce al motore di ASP.NET di reindirizzare l'utente alla pagina di errore personalizzata. Il contenuto della pagina di errore personalizzata viene invece restituito come risposta alla pagina che ha generato l'errore.
Riepilogo
Quando si verifica un'eccezione non gestita in un'applicazione Web ASP.NET, il runtime di ASP.NET genera l'evento Error
e visualizza la pagina di errore configurata. È possibile informare lo sviluppatore dell'errore, registrarne i dettagli o elaborarlo in altro modo creando un gestore eventi per l'evento Error. Esistono due modi per creare un gestore eventi per HttpApplication
eventi come Error
: nel Global.asax
file o da un modulo HTTP. Questa esercitazione ha illustrato come creare un Error
gestore eventi nel Global.asax
file che informa gli sviluppatori di un errore tramite un messaggio di posta elettronica.
La creazione di un Error
gestore eventi è utile se è necessario elaborare eccezioni non gestite in modo univoco o personalizzato. Tuttavia, la creazione di un gestore eventi personalizzato Error
per registrare l'eccezione o per notificare a uno sviluppatore non è l'uso più efficiente del tempo perché esiste già disponibile e facile da usare librerie di registrazione degli errori che possono essere configurate in pochi minuti. Le due esercitazioni successive esaminano due librerie di questo tipo.
Buon programmatori!
Altre informazioni
Per altre informazioni sugli argomenti illustrati in questa esercitazione, vedere le risorse seguenti:
- Panoramica dei moduli HTTP e dei gestori HTTP ASP.NET
- Risposta normale alle eccezioni non gestite - Elaborazione di eccezioni non gestite
HttpApplication
Classe e l'oggetto Application ASP.NET- Gestori HTTP e moduli HTTP in ASP.NET
- Invio di messaggi di posta elettronica in ASP.NET
- Informazioni sul
Global.asax
file - Uso di moduli HTTP e gestori per creare componenti di ASP.NET collegabili
- Utilizzo del file ASP.NET
Global.asax
- Uso delle
HttpApplication
istanze