Exceções podem ser definidas, em termos gerais, como instâncias de classes empregadas na representação de erros que aconteceram ao longo da execução de uma aplicação. Trata-se de um mecanismo presente não apenas no .NET Framework, como também em outras plataformas de desenvolvimento como Java, por exemplo.
Tomando por base a plataforma .NET, todas as exceções manipuladas dentro desta derivam da classe básica Exception (namespace System). Este é o caso de tipos que definem erros bastante comuns em aplicações baseadas no framework .NET, tais como SqlException (exceção gerada ao ocorrerem erros no acesso a uma base de dados do SQL Server), DivideByZeroException (erro disparado ao se tentar efetuar uma divisão por zero), OutOfMemoryException (lançada quando não existir memória suficiente para a execução de uma operação) e SecurityException (este erro acontece quando um problema de segurança for detectado, como por exemplo a tentativa de acesso a um diretório para o qual se retiraram as permissões de leitura).
Além dos exemplos de exceções que foram citados, o .NET Framework disponibiliza nativamente um grande número de outros tipos que correspondem a erros, com cada uma dessas classes se destinando à representação de falhas em cenários gerais. No entanto, haverá situações nas quais desenvolvedores precisarão criar uma ou mais classes a serem empregadas para se lançarem erros bem específicos: a estas estruturas dá-se o nome de exceções customizadas.
A própria documentação da plataforma .NET estabelece algumas diretrizes a serem consideradas na implementação de exceções customizadas:
- A classe-filha derivar, sempre que possível, do tipo Exception ou de outra classe básica;
- Evitar hierarquias extensas, ou seja, criar vários níveis de exceções, em que um tipo herda do outro;
- É extremamente aconselhável que o nome da exceção terminar com o sufixo Exception, de maneira a identificar mais facilmente a finalidade a que se presta a classe em questão.
Procurando demonstrar os conceitos até aqui mencionados, será criado um exemplo de exceção customizada, empregando-se o mesmo em uma aplicação ASP.NET detalhada nas próximas seções deste artigo.
Criando a solução de exemplo
A aplicação apresentada neste artigo foi criada no .NET framework 4.0, através da utilização do Microsoft Visual Studio 2010 Ultimate Edition (o conteúdo pode ser baixado a partir de um link para download que se encontra nesta página). O exemplo demonstrado a seguir procura abordar a implementação de uma exceção customizada, bem como o tratamento desta em um projeto ASP.NET Web Forms. O
site aqui detalhado contará com uma funcionalidade para o cálculo do IMC (Índice de Massa Corpórea) de uma pessoa.
Para gerar o projeto de testes será necessário, dentro do Visual Studio, acessar o menu File, opção New, sub opção Project. Dentro da tela New Project (Figura 1) selecionar o template ASP.NET Web Application, preenchendo o campo Name com o nome da aplicação a ser gerada (“TesteExceptions”, neste caso); no campo Location é possível ainda definir o diretório no qual serão criados os arquivos para este projeto.
Criação das classes para os testes com exceções customizadas
Com o projeto TesteExceptions criado, será necessário prosseguir com a geração das classes a serem utilizadas na implementação da aplicação de testes, bem como no tratamento de erros ocorridos nesta. Primeiramente será implementada a classe IMCException. Clique dentro do Solution Explorer com o botão direito do mouse sobre a Web Application TesteExceptions, escolhendo em seguida no menu de atalho a opção Add, sub opção New Item. Neste momento será exibida a tela Add New Item (Figura 2); preencher o campo Name com “IMCException.cs”.
A Listagem 1 apresenta a implementação da classe IMCException, a qual herda do tipo básico Exception. Essa estrutura corresponde a uma exceção que será disparada quando ocorrer uma falha em uma operação de cálculo do IMC de uma pessoa. Valores inválidos de altura e/ou peso ou, até mesmo, uma falha durante o cálculo (divisão por zero) serão alguns dos motivos que podem levar à geração de um erro através de uma instância de IMCException.
O construtor definido para o tipo IMCException recebe como parâmetro uma mensagem, a qual descreve o problema que ocasionou a exceção. Este construtor acessa ainda os elemento de mesmo tipo que foi definido na classe básica Exception. Isso acontece, em ambos os casos, através da invocação da palavra-chave base, a qual tem por função redirecionar a chamada para o construtor implementado na classe-pai. O aproveitamento dos construtor definido em Exception permite ao tipo IMCException evitar a implementação de características que já foram codificadas na estrutura-pai.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace TesteExceptions
{
public class IMCException : Exception
{
public IMCException(string mensagem)
: base(mensagem)
{
}
}
}
O tipo IMC (Listagem 2) será empregado no cálculo do IMC de uma pessoa. Essa estrutura representa um exemplo de classe estática, ou seja, que não dependerá da geração de uma nova instância de objeto para a sua utilização de funcionalidades definidas na mesma.
Será a partir do método estático CalcularIMC que ocorrerá o processamento de informações de peso e altura de uma pessoa, obtendo-se a partir disto o Índice de Massa Corpórea (IMC) da mesma. Os dois parâmetros recebidos por esta operação (pesoPessoa e alturaPessoa) foram declarados como sendo do tipo object, o que significa que qualquer tipo de informação poderá ser fornecida a estes métodos (valores string ou, mesmo, já convertidos para um tipo numérico como double).
Inicialmente, CalcularIMC acessa a operação ConverterParametroIMC, a fim de transformar as medidas passadas como parâmetro em valores do tipo double, os quais serão associados às variáveis pesoConvertido e alturaConvertida.
Já no método estático ConverterParametroIMC, procede-se primeiramente com a conversão da medida que foi informada como parâmetro. Isto é feito através de uma chamada à operação ToDouble definida na classe Convert, com todo este processo acontecendo dentro de um bloco try-catch. Caso ocorram erros, o fluxo de execução é direcionado para a cláusula catch; uma nova instância da exceção IMCException é então criada, com o construtor recebendo como parâmetros uma mensagem que indica a ocorrência de uma falha na conversão (mensagemErroConversao).
Se o valor convertido no interior da operação ConverterParametroIMC corresponder a um número menor ou igual a zero, também será lançada uma exceção do tipo IMCException (a partir da mensagem associada ao parâmetro mensagemFaixaInvalidaValor).
A ocorrência de qualquer erro ao se chamar a operação ConverterParametroIMC fará com que o método CalcularIMC aborte a sua execução, sem continuar desse modo com o cálculo do IMC. A determinação deste valor também ocorre dentro de um bloco try-catch; na eventualidade de algum problema que aconteça durante o processamento da expressão para se chegar ao valor esperado, um erro também baseado em IMCException será disparado (novamente dentro de uma cláusula catch).
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace TesteExceptions
{
public static class IMC
{
private static double ConverterParametroIMC(
object valor,
string mensagemErroConversao,
string mensagemFaixaInvalidaValor)
{
double valorConvertido;
try
{
valorConvertido = Convert.ToDouble(valor);
}
catch
{
throw new IMCException(mensagemErroConversao);
}
if (valorConvertido <= 0)
{
throw new IMCException(mensagemFaixaInvalidaValor);
}
return valorConvertido;
}
public static double CalcularIMC(
object pesoPessoa, object alturaPessoa)
{
double pesoConvertido = ConverterParametroIMC(
pesoPessoa,
"Erro durante a conversão do Peso.",
"O Peso informado dever ser maior do que zero.");
double alturaConvertida = ConverterParametroIMC(
alturaPessoa,
"Erro durante a conversão da Altura.",
"A Altura informada dever ser maior do que zero.");
try
{
return (pesoConvertido /
(alturaConvertida * alturaConvertida));
}
catch
{
throw new IMCException(
"Erro durante o cálculo do IMC.");
}
}
}
}
Implementação do site para testes
Para a implementação da Web Application TesteExceptions foi utilizado o template padrão que é disponibilizado pelo Visual Studio. Em virtude disto, algumas mudanças nas páginas que foram criadas automaticamente estarão sendo feitas conforme especificado a seguir, a fim de tornar mais simples a aparência e a estrutura da aplicação de exemplo.
Na Listagem 3 encontra-se o código que define a aparência da Master Page Site.Master, a qual é referenciada pelas demais páginas do site. Esse tipo de estrutura conta normalmente com elementos visuais (menus, abas, legendas etc.) comuns às várias páginas de uma aplicação. Assim, a utilização deste recurso evita a replicação de controles e outros itens ao longo de uma solução Web (algo que dificultaria atividades de manutenções futuras).
Já a Listagem 4, apresenta o código que determina como a página Sobre (About.aspx) será visualizada via browser. O atributo MasterPageFile definido dentro da declaração inicial da página especifica que a mesma faz uso da Master Page Site.Master.
<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="Site.master.cs" Inherits="TesteExceptions.SiteMaster" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head runat="server">
<title></title>
<link href="~/Styles/Site.css" rel="stylesheet" type="text/css" />
<asp:ContentPlaceHolder ID="HeadContent" runat="server">
</asp:ContentPlaceHolder>
</head>
<body>
<form runat="server">
<div class="page">
<div class="header">
<div class="title">
<h1>
Teste do uso de Exceptions em Aplicações ASP.NET
</h1>
</div>
<div class="clear hideSkiplink">
<asp:Menu ID="NavigationMenu" runat="server"
CssClass="menu" EnableViewState="false"
IncludeStyleBlock="false"
Orientation="Horizontal">
<Items>
<asp:MenuItem NavigateUrl="~/Default.aspx"
Text="Home" />
<asp:MenuItem NavigateUrl="~/About.aspx"
Text="Sobre" />
</Items>
</asp:Menu>
</div>
</div>
<div class="main">
<asp:ContentPlaceHolder ID="MainContent" runat="server" />
</div>
<div class="clear">
</div>
</div>
<div class="footer">
</div>
</form>
</body>
</html>
<%@ Page Title="Sobre" Language="C#" MasterPageFile="~/Site.master"
AutoEventWireup="true"
CodeBehind="About.aspx.cs" Inherits="TesteExceptions.About" %>
<asp:Content ID="HeaderContent" runat="server"
ContentPlaceHolderID="HeadContent">
</asp:Content>
<asp:Content ID="BodyContent" runat="server"
ContentPlaceHolderID="MainContent">
<h2>
Sobre
</h2>
<p>
Esta é uma aplicação para teste do uso de
Exceptions em ASP.NET.
</p>
</asp:Content>
Será necessário agora prosseguir com a implementação da funcionalidade para cálculo do IMC. Isto acontecerá dentro da página Default.aspx, a qual foi gerada de maneira automática ao se criar o projeto TesteExceptions.
Adicionar ao formulário CalculoIMC.aspx dois controles TextBox (campos de peso e altura), um Button (o valor da propriedade Text deste componente será “Calcular IMC”) e, por fim, dois do tipo Label (conforme indicado na Tabela 1). Estes componentes serão utilizados no cálculo do IMC de uma pessoa, determinando ainda se está última encontra-se dentro da faixa de peso normal ou não.
Tipo do Controle | Nome do Controle |
TextBox | txtPeso |
TextBox | txtAltura |
Button | btnCalcularIMC |
Label | lblValorIMC |
Label | lblSituacaoPessoa |
A Figura 3 corresponde, em termos gerais, a um exemplo de como poderá ficar a página Default.aspx ao término dos procedimentos mencionados nesta seção. Esta imagem foi gerada a partir da execução da aplicação e do acesso a esta última via Internet Explorer.
Ao clicar no botão btnCalcularIMC será realizado o cálculo do IMC. O evento que corresponde a esta ação é demonstrado na Listagem 5. O método btnCalcularIMC_Click faz uso da classe IMC, invocando a operação CalcularIMC (que recebe como parâmetros as medidas digitadas nos campos disponíveis em tela) e exibindo o valor correspondente (variável valorIMC) e a situação do peso da pessoa em tela.
...
protected void btnCalcularIMC_Click(object sender, EventArgs e)
{
double valorIMC = IMC.CalcularIMC(txtPeso.Text, txtAltura.Text);
lblValorIMC.Text = valorIMC.ToString();
if (valorIMC < 18.5)
lblSituacaoPessoa.Text = "Abaixo do Peso";
else if (valorIMC > 25)
lblSituacaoPessoa.Text = "Acima do Peso";
else
lblSituacaoPessoa.Text = "Peso Normal";
}
...
Caso ocorram erros durante o processo de cálculo do IMC, será apresentada ao usuário uma tela similar à que consta na Figura 4. Embora para efeitos de desenvolvimento as informações exibidas no browser sejam úteis, não é recomendável se exibir isto a um usuário convencional: uma boa prática neste caso, seria a criação de uma página mais amigável indicando a ocorrência de um erro. Além disso, pessoas com um maior conhecimento podem, a partir das informações presentes numa tela de erro default do ASP.NET, explorar prováveis vulnerabilidades do sistema considerado.
O ASP.NET permite que uma página customizada para exibição de erros seja criada, com o formulário correspondente sendo exibido sempre que uma exceção não for tratada dentro de uma página da aplicação. Este é um recurso que permite centralizar a exibição de mensagens de erro, customizando as informações que são apresentadas aos usuários do site em questão.
Para a criação da página que centraliza a apresentação de erros será criado o formulário Erro.aspx. A geração dos arquivos correspondentes a esta Web Page é feita clicando-se com o botão direito do mouse sobre a Web Application TesteExceptions e selecionando no menu de atalho a opção Add, subopção New Item. Neste momento será exibida a tela Add New Item (Figura 5); marcar o template “Web Form using Master Page” e preencher o campo Name com “TesteSessionViewState.aspx”.
Clicando no botão “Add” será solicitado ao usuário que defina qual a Master Page para o Web Form que está sendo montado (Figura 6). A única opção possível no caso é “Site.Master”; finalizar então este processo acionando a opção “OK”.