ASP .NET - Web Forms Tratando erros (revisitado)


O tratamento de erros é fundamental para que sua aplicação seja gerenciada de forma robusta e consistente. Sem isso você fica a mercê do acaso e não sabe como proceder quando coisas inesperadas ocorrem em sua aplicação.

Eleve isso ao quadrado quando sua aplicação é uma aplicação web.

Para efetuar o tratamento a nível de aplicação, você deve usar o evento Application_Error no arquivo Global. asax; este evento ocorre para qualquer exceção não tratada na aplicação.

Podemos realizar esta tarefa cumprindo as seguintes etapas:

  1. Criar um tratamento para o evento Page_Error;
  2. Relançar as páginas de erros a partir dos métodos;
  3. Criar um tratamento para o evento Application_Error;
  4. Criar uma mensagem detalhada e escrevê-la no log de eventos;
  5. Redirecionar o usuário para a página de erro usando Server.Transfer;

Neste artigo vou traçar uma estratégia básica para tratamento de erros em aplicações ASP .NET Web Forms, sim porque para ASP .NET MVC o caminho é diferente.

1 - Tratando erro no nível de métodos

a- Se os erros potenciais são recuperáveis na rotina

Utilize uma combinação de blocos try...catch como mecanismo para o tratamento de erros

b- Se uma informação útil puder ser adicionada ao tratamento de exceção

Crie e lance uma nova exceção com a informação anexa

c- Se a liberação de recursos é requerida

Realize esta liberação de recursos no bloco finally

d- Se erros potenciais não podem ser recuperados na rotina

A recuperação deverá ser tratada pela rotina chamadora e sua estrutura de tratamento de erros

O esquema básico fica retratado pelo seguinte código:

Private Sub Rotina( )
...

Try
 
 'Código a ser executado pela rotina
Catch exc As Exception
  
 'Tratamento de erros
Finally
  
 'Liberação de recursos
End Try

End Sub

private void Rotina( )
{
  try
  {
     
// Código da rotina
  }
  catch (Exception exc)
  {
    
// Tratamento de erros
  }
  finally
  {
    
// Liberação de recursos
  }
}
VB .NET C#
  1. O bloco Try/try contém o código que implementa o método/rotina
  2. O bloco Catch/catch, que é opcional, inclui o código que trata erros específicos mais prováveis de ocorrer e recuperar
  3. O bloco Finally/finally, que é opcional, realiza a liberação requerida. Isso inclui o fechamento de conexões de banco de dados usadas, liberação de objetos criados pelo método, etc. O código deste bloco sempre será executado.

Tabela com orientação para definição do bloco Try... Catch...Finally

Podem ocorrer erros ? Os erros são recuperáveis ? Uma informação de contexto
pode ser adicionada
É exigida liberação ? Combinação Recomendada
Não - x - - x - Não  Nenhuma
Não - x - - x - Sim Try e Finally
Sim Não Não Não  Nenhuma
Sim Não Não Sim Try e Finally
Sim Não Sim Não Try e Catch
Sim Não Sim Sim  Try, Catch e Finally
Sim Sim - x - - x -  Try e Catch

Lembre-se que o .NET Framework não fecha conexões, arquivos, etc. quando ocorre um erro. isso é responsabilidade do programador e deve ser feita no bloco finally, este bloco é a última oportunidade para realizar qualquer liberação antes da infraestrutura de tratamentos de exceção tomar conta da aplicação.

Para ajudar a sua implementação da sua rotina de tratamento de erros temos a seguir um questionário onde com base em suas respostas você pode determinar qual parte do bloco try...catch...finally você irá precisar implementar.

1- Pode ocorrer algum erro nesta rotina ?

R: Se não, então nenhum código para tratamento de erros é requerido.

2- Os erros potenciais são recuperáveis na rotina ?

R: Se ocorreu um erro, mas nada de útil pode ser feito na rotina, a exceção deve ser propagada para a rotina de chamada. Não serve a nenhum propósito útil capturar a exceção e relançá-la.
Esta questão é diferente de :
"São os erros potenciais recuperáveis a nível de aplicativo ?"
Por exemplo, se a rotina tenta gravar um registro em um banco de dados e encontra o registro bloqueado, uma nova tentativa pode ser feita na rotina. No entanto, se um valor é passado para a rotina e as operações resultam em um outro erro, a recuperação não pode ser realizada na rotina, mas deve ser manuseado pela rotina de chamada e a sua estrutura de manipulação de erros

3- Uma informação útil pode ser adicionada à exceção ?

R: As exceções que ocorrem no .NET Framework contém informações detalhadas sobre o erro. No entanto, as exceções não fornecem qualquer informação de contexto sobre o que estava sendo tentado no nível do aplicativo que pode ajudar a solucionar o erro ou fornecer informações mais úteis para o usuário.

Uma nova exceção pode ser criada e lançada com as informações adicionadas. O primeiro parâmetro para o objeto da nova exceção deve conter a mensagem de contexto útil, e o segundo parâmetro deve ser a exceção original. Os mecanismos de tratamento de exceção no .NET Framework criam uma lista ligada de objetos de exceção para criar uma trilha a partir da raiz da exceção até o nível onde a exceção é tratada. Ao passar a exceção original como o segundo parâmetro, a lista encadeada da exceção de raiz é mantida. Exemplo:

Catch exc As Exception
     Throw New Exception("Mensagem de contexto", exc)  
VB .NET
catch (Exception exc)
{
    throw (new Exception("Mensagem de contexto", exc));
}
C#

Para encerrar temos a seguir um código que mostra a utilização de bloco try/catch no interior de laço while para fornecer um mecanismo de tratamento de exceção onde definimos um número de tentativas para que a rotina seja executada novamente:

using System;
using System.Configuration;
using System.Data;
using System.Data.OleDb;

	private void atualizaDados(int problemID,String sectionHeading)
	{
		const int NUM_MAX_TENTATIVAS = 5;

		OleDbConnection dbConn = null;
		OleDbCommand dCmd = null;
		String strConnection = null;
		String cmdText = null;
		bool updateOK;
		int retryCount;

		try
		{
			 // obtem a string de conexão do arquivo web.config e abre a conexão
 		                 strConnection = ConfigurationManager.ConnectionStrings["dbConnectionString"].ConnectionString;
			 dbConn = new OleDbConnection(strConnection);
			 dbConn.Open( );

			 // constrói a instrução SQL para atualizar o registro no banco de dados
			 cmdText = "UPDATE Teste " +
          				    "SET nome='" + _nome + "' " +
	          			   "WHERE codigo=" + codigoID.ToString( );

			dCmd = new OleDbCommand(cmdText, dbConn);
         			// fornece um laço com um bloco try catch para facilitar a tentativa de atualização 
			atualizacaoOK = false;
			tentativas = 0;
			while ((!atualizacaoOK) &  (tentativas < NUM_MAX_TENTATIVAS))
			{
			     try
			     {
   				     dCmd.ExecuteNonQuery( );
    				     atualizacaoOK = true;
			     } 
			     catch (Exception exc)
			     {
   				     tentativas++;
   				     if (tentativas >= NUM_MAX_TENTATIVAS)
   				     {
     				          //lança uma nova exceção com a mensagem de contexto informando que o número de 
     				         // tentativas foi excedida
        				        throw new Exception("Máximo de tentativas excedida",exc);
			                    }
         	  	                     }    
 		                 }//bloco while
		} 
		finally
		{
			// libera recursos
			if (dbConn != null)
			{
				dbConn.Close( );
			}
           	               } 
	} 

No código acima observe que temos um bloco try...finally que trata o código para abertura da conexão e atualização da tabela no bloco try e libera os recursos no bloco finally.

Os mecanismos de tratamento de exceções no .NET Framework são poderosos. Além do escopo que abordamos neste artigo, outros tipos de exceções específicas podem ser capturadas e processadas de forma diferente.

Além disso, você pode criar novas classes de exceção herdando as classes de exceção base e adicionando a funcionalidade exigida por seus aplicativos.

João 7:28 Jesus, pois, levantou a voz no templo e ensinava, dizendo: Sim, vós me conheceis, e sabeis donde sou; contudo eu não vim de mim mesmo, mas aquele que me enviou é verdadeiro, o qual vós não conheceis.

João 7:29 Mas eu o conheço, porque dele venho, e ele me enviou.

        Gostou ?   Compartilhe no Facebook   Compartilhe no Twitter

Referências: