Processamento de exceções sem tratamento (C#)
por Scott Mitchell
Exibir ou baixar código de exemplo (como baixar)
Quando ocorre um erro de runtime em um aplicativo Web em produção, é importante notificar um desenvolvedor e registrar o erro para que ele possa ser diagnosticado posteriormente. Este tutorial fornece uma visão geral de como ASP.NET processa erros de runtime e analisa uma maneira de fazer com que o código personalizado seja executado sempre que uma exceção sem tratamento surgir até o runtime do ASP.NET.
Introdução
Quando ocorre uma exceção sem tratamento em um aplicativo ASP.NET, ela se propaga até o runtime do ASP.NET, o que aciona o Error
evento e exibe a página de erro apropriada. Há três tipos diferentes de páginas de erro: o erro de runtime YSOD (tela amarela de morte); os detalhes da exceção YSOD; e páginas de erro personalizadas. No tutorial anterior , configuramos o aplicativo para usar uma página de erro personalizada para usuários remotos e o YSOD de Detalhes da Exceção para usuários que visitam localmente.
Usar uma página de erro personalizada amigável que corresponda à aparência do site é preferencial para o YSOD de erro de runtime padrão, mas exibir uma página de erro personalizada é apenas uma parte de uma solução abrangente de tratamento de erros. Quando ocorre um erro em um aplicativo em produção, é importante que os desenvolvedores sejam notificados sobre o erro para que possam descobrir a causa da exceção e resolvê-la. Além disso, os detalhes do erro devem ser registrados para que o erro possa ser examinado e diagnosticado posteriormente.
Este tutorial mostra como acessar os detalhes de uma exceção sem tratamento para que eles possam ser registrados e um desenvolvedor notificado. Os dois tutoriais a seguir exploram bibliotecas de log de erros que, após um pouco de configuração, notificarão automaticamente os desenvolvedores sobre erros de runtime e registrarão seus detalhes.
Observação
As informações examinadas neste tutorial serão mais úteis se você precisar processar exceções sem tratamento de alguma maneira exclusiva ou personalizada. Nos casos em que você só precisa registrar a exceção e notificar um desenvolvedor, usar uma biblioteca de log de erros é o caminho a percorrer. Os próximos dois tutoriais fornecem uma visão geral de duas dessas bibliotecas.
Executando código quando oError
evento é gerado
Os eventos fornecem a um objeto um mecanismo para sinalizar que algo interessante ocorreu e para outro objeto executar código em resposta. Como desenvolvedor ASP.NET, você está acostumado a pensar em termos de eventos. Se você quiser executar algum código quando o visitante clicar em um botão específico, crie um manipulador de eventos para o evento desse Click
Botão e coloque seu código lá. Considerando que o runtime do ASP.NET gera seu Error
evento sempre que ocorre uma exceção sem tratamento, ele segue o código para registrar os detalhes do erro em um manipulador de eventos. Mas como você cria um manipulador de eventos para o Error
evento?
O Error
evento é um dos muitos eventos na HttpApplication
classe que são gerados em determinados estágios no pipeline HTTP durante o tempo de vida de uma solicitação. Por exemplo, o HttpApplication
evento da BeginRequest
classe é gerado no início de cada solicitação; seu AuthenticateRequest
evento é gerado quando um módulo de segurança identifica o solicitante. Esses HttpApplication
eventos dão ao desenvolvedor da página um meio de executar a lógica personalizada nos vários pontos no tempo de vida de uma solicitação.
Os manipuladores de eventos para os HttpApplication
eventos podem ser colocados em um arquivo especial chamado Global.asax
. Para criar esse arquivo em seu site, adicione um novo item à raiz do seu site usando o modelo classe de aplicativo global com o nome Global.asax
.
Figura 1: Adicionar Global.asax
ao seu aplicativo Web
(Clique para exibir a imagem em tamanho real)
O conteúdo e a estrutura do Global.asax
arquivo criado pelo Visual Studio diferem ligeiramente com base em se você está usando um WAP (Projeto de Aplicativo Web) ou um WSP (Projeto de Site). Com um WAP, o Global.asax
é implementado como dois arquivos separados – Global.asax
e Global.asax.cs
. O Global.asax
arquivo não contém nada além de uma @Application
diretiva que faz referência ao .cs
arquivo; os manipuladores de eventos de interesse são definidos no Global.asax.cs
arquivo. Para WSPs, apenas um único arquivo é criado, Global.asax
e os manipuladores de eventos são definidos em um <script runat="server">
bloco.
O Global.asax
arquivo criado em um WAP pelo modelo classe de aplicativo global do Visual Studio inclui manipuladores de eventos chamados Application_BeginRequest
, Application_AuthenticateRequest
e Application_Error
, que são manipuladores de eventos para os HttpApplication
eventos BeginRequest
, AuthenticateRequest
e Error
, respectivamente. Também há manipuladores de eventos chamados Application_Start
, Session_Start
, Application_End
e Session_End
, que são manipuladores de eventos que são acionados quando o aplicativo Web é iniciado, quando uma nova sessão é iniciada, quando o aplicativo termina e quando uma sessão termina, respectivamente. O Global.asax
arquivo criado em um WSP pelo Visual Studio contém apenas os Application_Error
manipuladores de eventos , Application_Start
, Session_Start
, Application_End
e Session_End
.
Observação
Ao implantar o aplicativo ASP.NET, você precisa copiar o Global.asax
arquivo para o ambiente de produção. O Global.asax.cs
arquivo, que é criado no WAP, não precisa ser copiado para produção porque esse código é compilado no assembly do projeto.
Os manipuladores de eventos criados pelo modelo classe de aplicativo global do Visual Studio não são exaustivos. Você pode adicionar um manipulador de eventos para qualquer HttpApplication
evento nomeando o manipulador de eventos Application_EventName
. Por exemplo, você pode adicionar o seguinte código ao Global.asax
arquivo para criar um manipulador de eventos para o AuthorizeRequest
evento:
protected void Application_AuthorizeRequest(object sender, EventArgs e)
{
// Event handler code
}
Da mesma forma, você pode remover todos os manipuladores de eventos criados pelo modelo classe de aplicativo global que não são necessários. Para este tutorial, precisamos apenas de um manipulador de eventos para o Error
evento; fique à vontade para remover os outros manipuladores de eventos do Global.asax
arquivo.
Observação
Os módulos HTTP oferecem outra maneira de definir manipuladores de eventos para HttpApplication
eventos. Os módulos HTTP são criados como um arquivo de classe que pode ser colocado diretamente dentro do projeto de aplicativo Web ou separado em uma biblioteca de classes separada. Como eles podem ser separados em uma biblioteca de classes, os módulos HTTP oferecem um modelo mais flexível e reutilizável para criar HttpApplication
manipuladores de eventos. Enquanto o Global.asax
arquivo é específico para o aplicativo Web em que ele reside, os módulos HTTP podem ser compilados em assemblies. Nesse ponto, adicionar o Módulo HTTP a um site é tão simples quanto descartar o assembly na Bin
pasta e registrar o Módulo em Web.config
. Este tutorial não analisa a criação e o uso de módulos HTTP, mas as duas bibliotecas de log de erros usadas nos dois tutoriais a seguir são implementadas como Módulos HTTP. Para obter mais informações sobre os benefícios dos módulos HTTP, consulte Usando módulos e manipuladores HTTP para criar componentes de ASP.NET conectáveis.
Recuperando informações sobre a exceção sem tratamento
Neste ponto, temos um arquivo Global.asax com um Application_Error
manipulador de eventos. Quando esse manipulador de eventos é executado, precisamos notificar um desenvolvedor sobre o erro e registrar seus detalhes. Para realizar essas tarefas, primeiro precisamos determinar os detalhes da exceção que foi gerada. Use o método do GetLastError
objeto Server para recuperar detalhes da exceção sem tratamento que causou a ação do Error
evento.
protected void Application_Error(object sender, EventArgs e)
{
// Get the error details
HttpException lastErrorWrapper =
Server.GetLastError() as HttpException;
}
O GetLastError
método retorna um objeto do tipo Exception
, que é o tipo base para todas as exceções no .NET Framework. No entanto, no código acima, estou convertendo o objeto Exception retornado por GetLastError
em um HttpException
objeto . Se o Error
evento estiver sendo disparado porque uma exceção foi gerada durante o processamento de um recurso de ASP.NET, a exceção que foi gerada será encapsulada em um HttpException
. Para obter a exceção real que precipitou o evento Error, use a InnerException
propriedade . Se o Error
evento tiver sido gerado devido a uma exceção baseada em HTTP, como uma solicitação para uma página inexistente, um HttpException
será gerado, mas não terá uma exceção interna.
O código a seguir usa o GetLastErrormessage
para recuperar informações sobre a exceção que disparou o Error
evento, armazenando o HttpException
em uma variável chamada lastErrorWrapper
. Em seguida, ele armazena o tipo, a mensagem e o rastreamento de pilha da exceção de origem em três variáveis de cadeia de caracteres, verificando se é a lastErrorWrapper
exceção real que disparou o Error
evento (no caso de exceções baseadas em HTTP) ou se é apenas um wrapper para uma exceção que foi gerada durante o processamento da solicitação.
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;
}
Neste ponto, você tem todas as informações necessárias para escrever código que registrará os detalhes da exceção em uma tabela de banco de dados. Você pode criar uma tabela de banco de dados com colunas para cada um dos detalhes de erro de interesse - o tipo, a mensagem, o rastreamento de pilha e assim por diante - juntamente com outras informações úteis, como a URL da página solicitada e o nome do usuário conectado no momento. Application_Error
No manipulador de eventos, você se conectaria ao banco de dados e inseriria um registro na tabela. Da mesma forma, você pode adicionar código para alertar um desenvolvedor sobre o erro por email.
As bibliotecas de log de erros examinadas nos próximos dois tutoriais fornecem essa funcionalidade pronta para uso, portanto, não é necessário criar esse log de erros e notificação por conta própria. No entanto, para ilustrar que o Error
evento está sendo gerado e que o Application_Error
manipulador de eventos pode ser usado para registrar detalhes do erro e notificar um desenvolvedor, vamos adicionar código que notifica um desenvolvedor quando ocorre um erro.
Notificar um desenvolvedor quando ocorre uma exceção sem tratamento
Quando ocorre uma exceção sem tratamento no ambiente de produção, é importante alertar a equipe de desenvolvimento para que ela possa avaliar o erro e determinar quais ações precisam ser executadas. Por exemplo, se houver um erro ao se conectar ao banco de dados, você precisará dobrar marcar seu cadeia de conexão e, talvez, abrir um tíquete de suporte com sua empresa de hospedagem na Web. Se a exceção ocorreu devido a um erro de programação, código adicional ou lógica de validação pode precisar ser adicionado para evitar esses erros no futuro.
As classes .NET Framework no namespace facilitam o System.Net.Mail
envio de um email. A MailMessage
classe representa uma mensagem de email e tem propriedades como To
, From
, Subject
, Body
e Attachments
. O SmtpClass
é usado para enviar um MailMessage
objeto usando um servidor SMTP especificado; as configurações do servidor SMTP podem ser especificadas programaticamente ou declarativamente no <system.net>
elemento no Web.config file
. Para obter mais informações sobre como enviar mensagens de email em um aplicativo ASP.NET marcar meu artigo, Enviando Email de um site de Páginas da Web do ASP.NET e as perguntas frequentes do System.Net.Mail.
Observação
O <system.net>
elemento contém as configurações do servidor SMTP usadas pela SmtpClient
classe ao enviar um email. Sua empresa de hospedagem na Web provavelmente tem um servidor SMTP que você pode usar para enviar emails de seu aplicativo. Consulte a seção de suporte do host da Web para obter informações sobre as configurações do servidor SMTP que você deve usar em seu aplicativo Web.
Adicione o seguinte código ao Application_Error
manipulador de eventos para enviar um email a um desenvolvedor quando ocorrer um erro:
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);
}
Embora o código acima seja bastante longo, a maior parte dele cria o HTML que aparece no email enviado ao desenvolvedor. O código começa referenciando o HttpException
retornado pelo GetLastError
método (lastErrorWrapper
). A exceção real que foi gerada pela solicitação é recuperada por meio lastErrorWrapper.InnerException
de e é atribuída à variável lastError
. As informações de rastreamento de tipo, mensagem e pilha são recuperadas e armazenadas em três variáveis de lastError
cadeia de caracteres.
Em seguida, um MailMessage
objeto chamado mm
é criado. O corpo do email é formatado em HTML e exibe a URL da página solicitada, o nome do usuário conectado no momento e informações sobre a exceção (o tipo, a mensagem e o rastreamento de pilha). Uma das coisas interessantes sobre a HttpException
classe é que você pode gerar o HTML usado para criar a YSOD (Tela Amarela de Morte) dos Detalhes da Exceção chamando o método GetHtmlErrorMessage. Esse método é usado aqui para recuperar a marcação YSOD detalhes da exceção e adicioná-la ao email como um anexo. Uma palavra de cuidado: se a exceção que disparou o Error
evento for uma exceção baseada em HTTP (como uma solicitação para uma página inexistente), o GetHtmlErrorMessage
método retornará null
.
A etapa final é enviar o MailMessage
. Isso é feito criando um novo SmtpClient
método e chamando seu Send
método.
Observação
Antes de usar esse código em seu aplicativo Web, você desejará alterar os valores nas ToAddress
constantes e FromAddress
de para qualquer endereço de support@example.com email para o qual o email de notificação de erro deve ser enviado e originado. Você também precisará especificar as configurações do servidor SMTP na <system.net>
seção em Web.config
. Consulte seu provedor de host Web para determinar as configurações do servidor SMTP a serem usadas.
Com esse código em vigor sempre que houver um erro, o desenvolvedor recebe uma mensagem de email que resume o erro e inclui o YSOD. No tutorial anterior, demonstramos um erro de runtime visitando Genre.aspx e passando um valor inválido ID
por meio da querystring, como Genre.aspx?ID=foo
. Visitar a página com o Global.asax
arquivo em vigor produz a mesma experiência do usuário que no tutorial anterior – no ambiente de desenvolvimento, você continuará a ver a Tela Amarela de Morte dos Detalhes da Exceção, enquanto no ambiente de produção você verá a página de erro personalizada. Além desse comportamento existente, o desenvolvedor recebe um email.
A Figura 2 mostra o email recebido ao visitar Genre.aspx?ID=foo
. O corpo do email resume as informações de exceção, enquanto o YSOD.htm
anexo exibe o conteúdo mostrado no YSOD detalhes da exceção (consulte a Figura 3).
Figura 2: o desenvolvedor recebe uma notificação de Email sempre que há uma exceção sem tratamento
(Clique para exibir a imagem em tamanho real)
Figura 3: a notificação de Email inclui os detalhes da exceção YSOD como um anexo
(Clique para exibir a imagem em tamanho real)
E o uso da página de erro personalizada?
Este tutorial mostrou como usar Global.asax
e o Application_Error
manipulador de eventos para executar o código quando ocorre uma exceção sem tratamento. Especificamente, usamos esse manipulador de eventos para notificar um desenvolvedor de um erro; podemos estendê-lo para também registrar os detalhes do erro em um banco de dados. A presença do Application_Error
manipulador de eventos não afeta a experiência do usuário final. Eles ainda veem a página de erro configurada, seja o YSOD de Detalhes do Erro, o Erro de Runtime YSOD ou a página de erro personalizada.
É natural se perguntar se o arquivo e Application_Error
o Global.asax
evento são necessários ao usar uma página de erro personalizada. Quando ocorre um erro, o usuário é mostrado na página de erro personalizada, então por que não podemos colocar o código para notificar o desenvolvedor e registrar os detalhes do erro na classe code-behind da página de erro personalizada? Embora você certamente possa adicionar código à classe code-behind da página de erro personalizada, você não tem acesso aos detalhes da exceção que disparou o Error
evento ao usar a técnica que exploramos no tutorial anterior. Chamar o GetLastError
método da página de erro personalizada retorna Nothing
.
O motivo para esse comportamento é porque a página de erro personalizada é acessada por meio de um redirecionamento. Quando uma exceção sem tratamento atinge o ASP.NET runtime, o mecanismo de ASP.NET gera seu Error
evento (que executa o Application_Error
manipulador de eventos) e redireciona o usuário para a página de erro personalizada emitindo um Response.Redirect(customErrorPageUrl)
. O Response.Redirect
método envia uma resposta ao cliente com um código http 302 status, instruindo o navegador a solicitar uma nova URL, ou seja, a página de erro personalizada. Em seguida, o navegador solicita automaticamente essa nova página. Você pode dizer que a página de erro personalizada foi solicitada separadamente da página em que o erro se originou porque a barra de endereços do navegador é alterada para a URL da página de erro personalizada (consulte a Figura 4).
Figura 4: quando ocorre um erro, o navegador é redirecionado para a URL da página de erro personalizada
(Clique para exibir a imagem em tamanho real)
O efeito líquido é que a solicitação em que a exceção sem tratamento ocorreu termina quando o servidor responde com o redirecionamento HTTP 302. A solicitação subsequente para a página de erro personalizada é uma nova solicitação; nesse ponto, o mecanismo de ASP.NET descartou as informações de erro e, além disso, não tem como associar a exceção sem tratamento na solicitação anterior à nova solicitação para a página de erro personalizada. É por isso que GetLastError
retorna null
quando chamado da página de erro personalizada.
No entanto, é possível que a página de erro personalizada seja executada durante a mesma solicitação que causou o erro. O Server.Transfer(url)
método transfere a execução para a URL especificada e a processa na mesma solicitação. Você pode mover o código no Application_Error
manipulador de eventos para a classe code-behind da página de erro personalizada, substituindo-o Global.asax
pelo seguinte código:
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");
}
}
Agora, quando ocorre uma exceção sem tratamento, o manipulador de eventos transfere o Application_Error
controle para a página de erro personalizada apropriada com base no código http status. Como o controle foi transferido, a página de erro personalizada tem acesso às informações de exceção sem tratamento por meio Server.GetLastError
de e pode notificar um desenvolvedor sobre o erro e registrar seus detalhes. A Server.Transfer
chamada impede que o mecanismo de ASP.NET redirecione o usuário para a página de erro personalizada. Em vez disso, o conteúdo da página de erro personalizada é retornado como a resposta à página que gerou o erro.
Resumo
Quando ocorre uma exceção sem tratamento em um aplicativo Web ASP.NET, o runtime do ASP.NET gera o Error
evento e exibe a página de erro configurada. Podemos notificar o desenvolvedor sobre o erro, registrar seus detalhes ou processá-lo de alguma outra forma, criando um manipulador de eventos para o evento Error. Há duas maneiras de criar um manipulador de eventos para HttpApplication
eventos como Error
: no Global.asax
arquivo ou em um módulo HTTP. Este tutorial mostrou como criar um Error
manipulador de eventos no arquivo que notifica os Global.asax
desenvolvedores de um erro por meio de uma mensagem de email.
Criar um Error
manipulador de eventos será útil se você precisar processar exceções sem tratamento de alguma maneira exclusiva ou personalizada. No entanto, criar seu próprio Error
manipulador de eventos para registrar a exceção ou notificar um desenvolvedor não é o uso mais eficiente do seu tempo, pois já existem bibliotecas de log de erros gratuitas e fáceis de usar que podem ser configuradas em questão de minutos. Os próximos dois tutoriais examinam duas dessas bibliotecas.
Programação feliz!
Leitura Adicional
Para obter mais informações sobre os tópicos discutidos neste tutorial, consulte os seguintes recursos:
- Visão geral de módulos HTTP e manipuladores HTTP ASP.NET
- Respondendo normalmente a exceções sem tratamento – processando exceções sem tratamento
HttpApplication
Classe e o objeto application ASP.NET- Manipuladores HTTP e módulos HTTP no ASP.NET
- Enviando Email em ASP.NET
- Noções básicas sobre o
Global.asax
arquivo - Usando módulos e manipuladores HTTP para criar componentes de ASP.NET conectáveis
- Trabalhando com o arquivo ASP.NET
Global.asax
- Trabalhando com
HttpApplication
instâncias
Comentários
https://aka.ms/ContentUserFeedback.
Em breve: Ao longo de 2024, eliminaremos os problemas do GitHub como o mecanismo de comentários para conteúdo e o substituiremos por um novo sistema de comentários. Para obter mais informações, consulteEnviar e exibir comentários de