Debug de aplicações .NET e a propriedade InnerException

Veja neste artigo como o acesso à propriedade InnerException de uma exceção pode auxiliar no debug de aplicações .NET, esclarecendo informações sobre um erro que à primeira vista podem não ser tão claras.

Durante o desenvolvimento de aplicações ou, mesmo, com um sistema já em operação, não é um fato incomum que ocorram erros. As prováveis causas disto podem ser as mais variadas possíveis: descuidos por parte de programadores envolvidos em um projeto, uma funcionalidade não concluída conforme o esperado ou ainda, falhas decorrentes de algum elemento externo ao próprio software (servidores de banco de dados inoperantes, problemas em uma rede corporativa, falha no acesso a Web Services etc.) são apenas alguns dos fatores que podem conduzir a situações inesperadas e, em muitos casos, indesejáveis.

Considerando as principais plataformas de desenvolvimento atuais (com destaque para .NET e Java), erros são representados através de objetos conhecidos como exceções. A gravação de dados relativos a exceções geradas por uma aplicação se revela como um instrumento de extrema importância, visto que a partir destas informações desenvolvedores terão meios para tentar reproduzir falhas que afetaram um sistema.

No .NET Framework informações sobre exceções estão associadas a objetos baseados no tipo Exception (namespace System). O comum é que existam diferentes classes que herdam dessa construção básica, com cada uma das mesmas estando normalmente vinculadas a um contexto bem específico.

Sobre a estrutura da classe Exception, esta última conta com algumas propriedades que detalham um erro gerado dentro de uma aplicação:

A seguir estão listados alguns exemplos de exceções bastante comuns em aplicações construídas sob o .NET Framework:

A forma como estes problemas são registrados (técnica esta conhecida como "logging") é também bastante diversa, podendo envolver desde a persistência dos dados em tabelas de bases relacionais ou em mecanismos próprios de um sistema operacional (como o Event Viewer do Windows), passando até mesmo pela gravação em arquivos (no formato texto ou XML, por exemplo). Existem inclusive frameworks específicos que simplificam a implementação deste tipo de funcionalidade, sendo possível citar no caso do .NET Framework a geração de arquivos XML por meio do log4net (Log4net).

Independentemente da maneira como informações sobre exceções venham a ser gravadas, não será raro que programadores precisem se debruçar sobre o código-fonte, a fim de identificar em que situação uma falha poderá ocorrer. Muitas ferramentas visuais para desenvolvimento de software contam com mecanismos que facilitam tarefas desse gênero, sendo que a atividade relacionada ao uso de funcionalidades de execução de instruções e checagem de erros é conhecida como depuração ou, simplesmente, debug.

O Visual Studio oferece um amplo suporte para a depuração de soluções .NET. A partir do menu Debug está disponível uma série de opções para a execução passo a passo de trechos de uma aplicação, incluindo nisto as estruturas conhecidas como breakpoints.

Profissionais da área de software estão mais do que familiarizados com o poder e a flexibilidade que o uso de breakpoints oferece. Graças a esses recursos, é possível interromper o fluxo de execução de um sistema a partir de uma IDE de desenvolvimento, de maneira que se consiga inclusive executar instruções uma a uma, avaliando os dados e os resultados produzidos pelas mesmas. Trata-se, portanto, de um instrumento bastante importante para a simulação de situações que resultem em exceções.

Ainda sobre a interrupção no fluxo de execução de aplicações, o Visual Studio costuma indicar o ponto em que uma falha ocorreu, pausando assim o processamento atual. Quando isto acontece, a própria IDE permite a visualização da instância que corresponde à exceção gerada, facilitando assim o trabalho de análise a ser desempenhado por um desenvolvedor. Na Figura 1 é demonstrado um exemplo disto, em que a tentativa de se acessar uma base de dados resultou em um erro do tipo SqlException.

Figura 1: Visualizando informações sobre uma SqlException a partir do Visual Studio

Soluções construídas sob a tecnologia ASP.NET contam com algumas características peculiares no que se refere à geração de exceções. Conforme já mencionado anteriormente, um erro do tipo HttpUnhandledException será gerado caso uma falha não venha a ser tratada em aplicações Web. Esse comportamento pode vir a causar algumas dificuldades na depuração de uma aplicação, principalmente se um programador não se atentar a detalhes como a propriedade InnerException de uma exceção.

Supondo uma aplicação em que o evento Application_Error do arquivo Global.asax será responsável pela gravação de informações sobre erros, utilizando para isto uma classe de nome LogHelper (Listagem 1). O método Application_Error será acionado sempre que uma exceção não for tratada adequadamente dentro desta aplicação Web. Por meio do método GetLastError do objeto Server é possível se obter a instância da exceção que corresponde a tal erro.

Listagem 1: Evento Application_Error


  ...
  
  void Application_Error(object sender, EventArgs e)
  {
      Exception ex = Server.GetLastError();
      LogHelper.RegistrarErro(ex);
  }
  
  ...
  

Caso uma falha desconhecida esteja acontecendo na aplicação que se está considerando como exemplo, uma possível forma de se rastrear tal problema seria incluir um breakpoint dentro do evento Application_Error. A partir disto, torna-se possível verificar detalhes de prováveis exceções disparadas em outros pontos do sistema.

Uma vez que uma exceção seja lançada, pode-se visualizar o conteúdo de sua propriedade Message posicionando o mouse sobre a variável que armazena a mesma. Conforme demonstrado na Figura 2, a mensagem exibida é vaga demais, apenas indicando a ocorrência de um erro do tipo HttpUnhandledException.

Figura 2: Visualizando a mensagem associada a uma exceção

O botão “+” em que consta a mensagem vinculada a uma exceção permite verificar maiores detalhes sobre uma falha. Neste exemplo específico (Figura 3) nota-se que a propriedade InnerException foi preenchida com o erro original (uma exceção do tipo DivideByZeroException), o qual é decorrente de uma operação aritmética que resultou em divisão por zero.

Figura 3: Analisando o conteúdo da propriedade InnerException

O uso da propriedade InnerException é comum também em frameworks desenvolvidos por terceiros. Em tais casos, é provável que um erro inicial seja associado a um tipo de objeto mais genérico; nestas situações, apenas a consulta à propriedade InnerException poderá fornecer maiores informações na tentativa de se chegar à causa real de um problema.

Procurei com este artigo fornecer uma dica simples, mas que pode ser de grande utilidade ao se efetuar o debug de aplicações .NET. Espero que o conteúdo aqui apresentado possa auxiliá-lo em algum momento. Até uma próxima oportunidade!

Artigos relacionados