 VB .NET - Estratégia para Tratamento de exceções
VB .NET - Estratégia para Tratamento de exceções 
|  | Qual a melhor estratégia para efetuar o tratamento de exceções em uma aplicação ? Quais exceções devo utilizar ? Como efetuar um tratamento de exceções eficiente ? | 
Se você ainda tem estas dúvidas este artigo se propõe a mostrar como você pode montar uma estratégia de tratamento de exceções para aplicações VB.NET. Antes de prosseguir sugiro que você leia os artigos já publicados no site, se o assunto for novo para você.
Recordando rapidamente alguns conceitos básicos
O tratamento de exceções é implementado usando a estrutura de comandos : Try.. Catch...Finally..End Try cuja sintaxe básica é a seguinte:
| Try | 
| ' código que pode gerar/disparar uma exceção | 
| Catch | 
| ' código que efetua o tratamento da exceção | 
| Finally | 
| ' efetua a limpeza do código (fechamento de conexões, destruição de objetos usados , etc...) | 
| End Try | 
As instruções Try/End Try são obrigatórias. As cláusulas Catch/Finally podem ser usadas no interior do bloco Try/End Try, mas pelo menos uma delas é de uso obrigatório. Você pode ter mais de um Catch no interior do bloco.
Você pode usar as exceções padrão que a plataforma .NET contém; todas elas derivam da classe base System.Exception. As exceções mais comuns estão listadas abaixo:
Você não esta limitado a usar somente as exceções que a .NET Framework oferece pode também criar e lançar as suas próprias exceções. Para disparar uma exceção você usa a cláusula Throw :
Throw new ArgumentOutOfRangeException
onde :
ArgumentOutOfRangeException - informa o tipo de exceção que esta sendo lançada.
Nesta altura eu já posso lançar a questão :
"Qual a melhor maneira de usar e tratar exceções em uma aplicação VB.NET ?"
Creio que você já está consciente que deve procurar capturar diferentes tipos de exceções e saber o que fazer com cada uma delas em uma aplicação VB.NET. Existirão momentos que você deverá lançar uma exceção avisando o usuário de forma amigável para o problema que esta ocorrendo em outras ocasiões você deverá efetuar um tratamento mas elaborado.
De forma geral existem três formas de abordar o problema de tratamento de exceções :
Você captura todas as exceções
Você passa adiante todas as exceções
Você cria sua própria exceção customizada e mapeia todas as exceções para esta classe.
A melhor forma de tratar o problema é a terceira opção onde você cria uma classe de exceção customizada. Quando você cria um tipo de exceção customizada você ganha controle em todas as propriedades da exceção e pode também incluir propriedades a sua classe customizada.
| Nota: A linguagem Java todos os métodos usam a instrução throw para lançar uma exceção. A instrução throw requer um argumento simples: um objeto que seja passível de ser lançado. Em Java objetos passíveis de serem lançados são instâncias de qualquer sub-classe da classe Throwable. Se você tentar lançar um objeto que não seja passível de ser lançado o compilador vai recusar na compilação do programa e indicar um erro. A cláusula throws especifica quais exceções o método pode lançar. Você usa a instrução throws na assinatura do método informando quais exceções está lançando. Na plataforma .NET não existe a cláusula throws na assinatura de métodos. Desta forma , você deve documentar explicitamente as exceções que esta lançando para que o usuário saiba. Parece que isto foi feito intencionalmente de forma a que se tenha um tratamento de erros centralizado. A plataforma .NET também não possui as Checked Excpetions que a linguagem Java Possui. | 
Vejamos um exemplo básico para que você entenda melhor:
Imagine o seguinte trecho de código :
| Function getCliente()
    As 
    Boolean Try Dim pessoa As String = Cliente.buscaCliente("Macoratti") Catch sqle As SqlException Throw New ClienteException("Não foi possível localizar o cliente", sqle) End TryEnd Function | 
Esta função realiza uma busca pelo cliente Macoratti e lança uma exceção do tipo ClienteException se houver um erro do tipo SqlException.
Percebeu que a exceção ClienteException não é uma exceção padrão do .NET Framework. De onde terá ela surgido ?
A resposta é : a exceção ClienteException é uma exceção personalizada que foi criada pelo usuário e que possui o seguinte código:
| PublicClass ClienteException 
    Inherits Exception Private minhaException_ As Exception 
 Public Sub New(ByVal mensagem As String, ByVal excMac As Exception) MyBase.New(mensagem, excMac) minhaException_ = excMac    
    End 
    Sub Return (minhaException_) End Function End Class | 
A classe de exceção customizada - ClienteException - entende a exceção real lançada como um argumento e transforma a mensagem de nível de sistema em outra mensagem para o nível da aplicação. Além disto você tem a exceção original que casou o erro como parte da nova instância do objeto exceção.(minhaException_)
A classe ClienteException usa dois argumentos : a mensagem (mensagem) que podemos exibir e a exceção real (excMac) que causou a exceção. Assim, para saber a real causa da exceção que disparou ClienteException, basta chamar o método getMinhaException().
Aplicando a estratégia
Vamos agora mostrar que a teoria funciona na prática. Vamos aplicar o conceito a uma pequena aplicação feita no VB2005 que faz acesso a um banco de dados Access - clientes.mdb.
1- Crie um novo projeto no Visual Basic 2005 e inclua uma nova classe chamada DataBaseException.vb com o seguinte código:
| PublicClass DataBaseException Inherits Exception 
 End Sub Public Sub New(ByVal message As String) MyBase.New(message) End Sub Public Sub New(ByVal mensagem As String, ByVal inner As Exception) MyBase.New(mensagem, inner) End Sub 
 
 | 
2- No formulário padrão form1.vb inclua os seguintes controles : Label, TextBox(txtCodigoCliente), Button(btnExibirDados) e ListView(lstaClientes) , conforme figura abaixo:

Agora vamos definir duas classes para tratar as seguintes exceções :
CustomerNotFoundException - lançada quando um cliente não for localizado na base de dados
DataBaseUnavaillableException - lançada quando o banco de dados não pode ser acessado
Inclua um novo módulo de classe de nome CustomerNotFoundException.vb com o seguinte código :
| PublicClass CustomerNotFoundException Inherits DataBaseException 
 Private codigoCliente_ As Long Public ReadOnly Property CodigoCliente() As Long GetReturn CodigoCliente End GetEnd Property Public Sub New(ByVal codigoCliente As Long) MyBase.New("Código do cliente não localizado.") codigoCliente_ = codigoCliente 
    End 
    Sub End Class | 
Agora Inclua um novo módulo de classe de nome DataBaseUnavaillableException.vb com o seguinte código :
| Public Class 
    DatabaseUnavailableException Inherits DataBaseException Public
	Sub
    New(ByVal 
    ex As System.Exception) End Class | 
Perceba que ambas as classes herdam da nossa classe customizada DataBaseException.vb que por sua vez herda de Exception.
Vamos criar também uma classe chamada Cliente cujo objetivo será acessar a base de dados e selecionar os dados dos clientes. Para isto inclua um novo módulo de classe chamado Cliente.vb e insira o seguinte código: :
| ImportsSystem.Data.oledb 
 
	 Private Shared telefone_ As String 
	
     
     ConectaBD(database, cn) GetDadosCliente(cn, CodigoCliente) DesconectaBD(cn) End Sub Private Sub ConectaBD(ByVal database As String, ByRef cn As OleDbConnection) 
 
	cn.ConnectionString =
    "Provider=Microsoft.Jet.OLEDB.4.0;Data Source="
	"""" & database 
    & """" cn.Open() Catch ex As Exception Throw New DatabaseUnavailableException(ex) 
    End 
	
    Try Private Sub DesconectaBD(ByRef cn As OleDbConnection) cn.Close() cn.Dispose() End Sub Private Sub GetDadosCliente(ByVal cn As OleDbConnection, ByVal codigoCliente As Long) 
 Dim cmd As New OleDbCommand Dim reader As OleDbDataReader 
 cmd.Connection = cn cmd.CommandText = "SELECT * FROM tblClientes WHERE codigo = " & codigoCliente reader = cmd.ExecuteReader 
 If reader.HasRows Then reader.Read() Codigo_ = reader.Item("Codigo") Nome_ = reader.Item("Nome") Endereco_ = reader.Item("Endereco") telefone_ = reader.Item("Telefone") Else Throw New CustomerNotFoundException(codigoCliente) End IfEnd Sub 
 ReadOnly Property codigo() GetReturn Codigo_ End GetEnd Property ReadOnly Property nome() Get Return Nome_ End GetEnd Property ReadOnly Property endereco() GetReturn Endereco_ End GetEnd Property ReadOnly Property telefone() GetReturn telefone_ End GetEnd Property 
 | 
Podemos usar o mesmo tratamento de exceção para conexão como SQL Server (no meu caso o SQL Server Express 2005). Estarei fazendo o acesso a tabela tblClientes do banco de dados Cadastro.mdf que foi criado clicando com o botão direito do mouse sobre o nome do projeto e a seguir selecionando Add -> New Item , selecionando em seguida a opção SQL DataBase com o nome de Cadastro.mdf.
Vamos criar um novo formulário - form2.vb - e incluir os seguintes controles neste formulário : Button (btnExibirDados) e DataGridView (dgv1), conforme figura abaixo:

Agora no evento Click do botão - Exibir Dados
| Private
    Sub 
    btnExibirDados_Click(ByVal 
    sender As System.Object,
    ByVal e 
    As System.EventArgs)
    Handles 
    btnExibirDados.Click 
    Dim connection 
    As SqlConnection = New 
    SqlConnection("Data  
     
     da.TableMappings.Add("Table", "tblClientes") 
     cmd.CommandType = System.Data.CommandType.Text da.SelectCommand = cmd Dim ds As DataSet = New DataSet("Clientes") da.Fill(ds) dgv1.DataSource = ds.Tables(0) Catch exception As SqlException Throw New DataBaseException(exception.Message, exception) Finally If Not connection Is Nothing Then connection.Dispose() End IfEnd Try End Sub | 
Nota: A string de conexão com o SQL Server 2005 foi obtida através do assistente de criação de Data Source.
Se testarmos os projetos criados veremos que as classes criadas para tratar as exceções funcionam perfeitamente. Fica a seu cargo melhorá-las.
Aguardo você no próximo artigo VB.NET...  
 
 
Referências: