.NET - Organizando o tratamento de erros - Nível de método
Se você esta 'mais perdido do que cachorro em dia de mudança' quando a questão é o tratamento de erros em sua aplicação este artigo pode ser a sua tábua de salvação (ou perdição).
Vou começar com o tratamento de erros no nível de métodos e mostrar uma forma (existem muitas outras formas) de organizar as coisas quando os erros ocorrerem em sua aplicação.
Vou usar os recursos e vantagens do tratamento estruturado de exceções da plataforma .net , portanto , esqueça as cláusulas On Error goto/Resume do Visual Basic 6 pois vamos usar a estrutura try/catch/finally.
A estratégia adotada para tratamento de erros esta resumida a seguir de acordo com o cenário :
1- Erros potenciais estão previstos e sendo tratados em uma rotina
Solução - Usar uma combinação de blocos try Catch como mecanismo de retorno para tratamento de erros;
2- Uma informação importante deve ser incluída na ocorrência da exceção
Solução - Criar e lançar(throw) um nova exceção com a informação anexada;
3- As variáveis/objetos/recursos usados na rotina devem ser liberados da memória
Solução - Realizar a operação de limpeza em um bloco finally
4- Erros potenciais não estão sendo tratados em uma rotina
Solução - A recuperação deve ser tratada pela rotina que fez a chamada no seu tratamento de erros
A estrutura de tratamento de erros da plataforma .NET pode ser usada de diversas formas.
Vejamos a sintaxe básica do bloco Try/Catch para VB.NET e C#:
Private Sub Rotina( ) Try 'Codigo a ser tratado Catch exc As Exception 'tratamento de erro Finally 'operação de limpeza End Try End Sub |
private void Rotina( ) { try { // Codigo a ser tratado } catch (Exception exc) { // tratamento de erro } finally { // operação de limpeza } } |
VB .NET | C# |
O bloco Try inclui o código que implementa o método.
O bloco Catch é opcional, e inclui o código que trata erros específicos que são identificados e recuperados quando possível.
O bloco finally é opcional,e realiza a operação de limpeza requerida antes que o método encerre devido a um erro ou não. Geralmente as operações referem-se ao fechamento de conexões com banco de dados , liberação de objetos criados no método, etc. O bloco finally sempre será executado quer ocorra ou não uma exceção.
Os blocos Catch e finally são opcionais mas você deve usar um deles obrigatoriamente.
De forma geral você deve usar a estrutura de tratamento de erros em qualquer método um erro possa ocorrer mas a técnica exata depende da circunstância. Veja abaixo um resumo dos possíveis cenários:
Erros podem ocorrer ? | São Recuperáveis? | Uma informação importante deve ser anexada ? | A limpeza é necessária ? | Combinação recomendada de blocos try, catch, e finally |
---|---|---|---|---|
Não | N/A | N/A | Sim | TRy e finally somente |
Sim | Não | Não | Não | Nenhum |
Sim | Não | Não | Sim | TRy e finally somente |
Sim | Não | Sim | Não | try e catch somente |
Sim | Não | Sim | Sim | try, catch, e finally |
Sim | Sim | N/A | N/A | try e catch only |
Nota: Lembre-se que o .NET Framework não fecha as conexões de banco de dados , arquivos ,etc quando erros ocorrem. Esta responsabilidade é do programados (ou seja SUA), e, você deve fazer isso no bloco finally pois esta é a última oportunidade de realizar as ações de limpeza antes que a infraestrutura do tratamento de exceção tome o controle da aplicação.
Para ajudá-lo a definir melhor a implementação de uma estratégia de tratamento de erros temos a seguir algumas questões cujas respostas podem ajudá-lo a tomar esta decisão:
1- Erros podem ocorrer durante a execução do código de uma rotina/método ?
Se a resposta for SIM, então implemente o tratamento usando o bloco try/catch.
Se um erro ocorre e nada pode ser
feito durante a execução do código, você deve propagar a
exceção a rotina que fez a chamada da rotina/método onde o
erro ocorreu.
Por exemplo se uma rotina tenta escrever um registro em uma
tabela de um banco de dados e encontra o registro bloqueado você
pode tentar efetuar a gravação mais uma vez (este erro é
recuperável).
Se um valor é passado para a rotina e durante a execução da
operação ocorre um erro de estouro de pilha a recuperação
não é possível na rotina mas pode ser tratada pela rotina que
fez a chamada do método no seu tratamento de erros.
Exceções que ocorrem na plataforma .NET contém informação detalhada relacionada ao erro; mas as exceções não fornecem qualquer informação de contexto sobre o que esta sendo feito a nível de aplicação no tratamento do erro ou no fornecimento de informação importante ao usuário.
Neste caso uma nova exceção pode ser criada e lançada com a informação necessária. O primeiro parâmetro para a nova exceção deverá conter a mensagem do contexto e o segundo deverá ser a exceção original. O mecanismo de tratamento de exceção da plataforma .NET cria uma linked list de objetos Exception de forma a criar um rastro a partir da exceção raiz até o nível onde a exceção foi tratada. Exemplo:
Catch
ex As Exception Throw New Exception("mensagem do contexto", ex) |
catch (Exception ex) { throw (new Exception("mensagem do contexto", ex)); } |
VB.NET | C# |
Um bloco Catch não deve ser usado no fluxo normal da sua aplicação.
O fluxo normal do programa deve ser colocado somente no bloco try e o fluxo anormal deve ser colocado no bloco Catch.
O mecanismo de tratamento de exceções da plataforma .NET é eficiente e poderoso; eu tratei neste artigo das exceções que ocorrem a nível de método/rotina mas outras exceções específicas podem ser capturadas e processadas diferentemente.
Você pode criar uma classe para tratamento de exceções que herda da classe base Exception e pode incluir funcionalidades requeridas pela sua aplicação nesta classe. Um exemplo desta técnica pode ser vista no código a seguir onde uma nova tentativa de atualização é feita após ocorrer o erro:
Imports System Imports System.Configuration Imports System.Data Imports System.Data.OleDb Private Sub atualizaDados(ByVal problemID As Integer, ByVal sectionHeading As String) Const MAX_TENTATIVAS As Integer = 5 Dim dbConn As OleDbConnection = Nothing Dim dCmd As OleDbCommand = Nothing Dim strConnection As String Dim cmdText As String Dim updateOK As Boolean Dim rContador As Integer Try 'obtem a string e conexão do arquivo web.config e abre a conexão strConnection = ConfigurationManager.ConnectionStrings("dbConnectionString").ConnectionString dbConn = New OleDbConnection(strConnection) dbConn.Open( ) 'cria um comando SQL update para atualizar o registro no banco de dados cmdText = "UPDATE EditProblem " & "SET SectionHeading='" & sectionHeading & "' " &_ "WHERE EditProblemID=" &problemID.ToString( ) dCmd = New OleDbCommand(cmdText, dbConn) 'fornece um laço com o bloco try/catch para facilitar a tentativa de atualizar o banco de dados updateOK = False rContador = 0 While ((Not updateOK) And (rContador < MAX_TENTATIVAS )) Try dCmd.ExecuteNonQuery( ) updateOK = True Catch ex As Exception rContador += 1 If (rContador >= MAX_TENTATIVAS) Then 'lança uma nova exceção com a mensagem de contexto informando 'o número máximo de tentativas que foram realizadas Throw New Exception("Número máximo de tentativas alcançada", ex) End If End Try End While Finally 'realiza a operação de limpeza If (Not IsNothing(dbConn)) Then dbConn.Close( ) End If End Try End Sub |
Option Explicit On Option Strict On ''' <summary> ''' Esta classe fornece uma classe de exceção com suporte a mensagem amigáveis ''' </summary> Public Class ExcecaoAmigavelVB Inherits System.ApplicationException 'define variável para copiar a mensasgem amigavel Private mMensagemAmigavel As String = "" '''*********************************************************************** ''' <summary> ''' Fornece o acesso a mensagem a ser exibida de forma amigável ''' message. ''' </summary> Public Property MensagemAmigavel ( ) As String Get Return (mMensagemAmigavel ) End Get Set(ByVal Value As String) mMensagemAmigavel = Value End Set End Property '''*********************************************************************** ''' <summary> ''' Fornece um construtor com suporte a mensagem de erro, uma referencia a ''' a exceção que lançou esta exceção e uma mensagem amigável. ''' </summary> Public Sub New(ByVal message As String, ByVal inner As Exception, _ ByVal MensagemAmigavel As String) 'chama o construtor da classe base MyBase.New(message, inner) mMenagemAmigavel = MensagemAmigavel End Sub 'New End Class |
Com esses conselhos espero ter contribuído para auxiliá-lo no gerenciamento do tratamento de erros da sua aplicação. Aguarde em breve um artigo sobre tratamento de erros em páginas ASP .NET.
Referências:
José Carlos Macoratti