segunda-feira, 23 de abril de 2007

[Vista] Obtendo o endereço IP da máquina no ASP

Para se obter o endereço IP da máquina cliente no Asp tradicional, pode-se consultar o valor da variável Request.ServerVariables("REMOTE_ADDR").

Porém percebi algo nas minhas tentativas de programar no Windows Vista. No Windows XP funcionava normal, retornava "127.0.0.1", quando executava da minha máquina. No Windows Vista, quando acesso esse valor, retorna "::1". Não sei o motivo, talvez seja culpa do ISS7, ou alguma configuração do Vista que protege o endereço IP. O Fato é que se a sua a aplicação consulta o IP da máquina, é bom prestar atenção nisso.

Não tentei acessar um servidor Vista de um cliente XP ou vice-versa, para isolar o problema no cliente ou servidor. Se alguém quiser fazer isso, poste um comentário com o resultado para compartilhar com os outros ;)

segunda-feira, 16 de abril de 2007

Tratamento de erros: Objeto Exception parte 3

InnerException

Nos dois últimos artigos falei sobre o objeto exception e suas principais características. Agora, para concluir, irei falar sobre uma propriedade importante do objeto Exception, a InnerException. Essa propriedade não é utilizada por muitas exceções, mas quando é utilizada, é importante analisá-la para obter informações mais completas a respeito do erro.

Se queremos tratar um erro apenas para adicionar informações extras a ele, mas sem perder o erro original, podemos encapsular esse erro em outro objeto exception. O erro original será referenciado pela propriedade InnerException desse erro original.

Como um exemplo da aplicação dessa técnica, imagine que esteja criando uma classe base de acesso a dados, com métodos como ExecutarProc ou coisa do tipo. Se você quiser que , quando um erro ocorrer ao executar uma proc, você queira informar o nome da procedure chamada, pode capturar o erro que ocorreu durante a execução, criar um novo erro com o nome da proc, e encapsular o erro original na propriedade InnerException do erro criado. Em um artigo futuro, irei falar sobre como criar suas próprias exceções, então falarei mais sobre InnerException.

Um exemplo no framework onde isso é utilizado, é na classe XmlSerializer. Esse classe server para gravar e carregar objetos em formato XML. Quando você carrega um xml com esse objeto, e o xml está mal formado, irá obter uma mensagem do tipo : "There is an error in the XML Document (Há um erro no documento XML)". Só essa mensagem não te ajuda muito a descobrir o problema com o arquivo. Mas se você analisar a propriedade InnerException da exceção gerada, verá outro objeto Exception com a mensagem que descreve exatamente qual o problema no xml.

Não existe um limite para a propriedade InnerException, pode ser criada uma cadeia de exceções, cada uma fornecendo um detalhe adicional sobre o erro. É importante, ao criar o mecanismo de tratamento de erros da sua aplicação analisar a propriedade InnerException da exceção (e das próprias InnerException), pois podem haver informações importantes lá.

quarta-feira, 11 de abril de 2007

[Vista] Permissão de administrador

O Windows vista restringe os acessos dos programas quando executados normalmente. Algumas vezes será necessário rodar o programa como privilégio de administrador para funcionar adequadamente.

Para fazer isso, clique com o botão direito no atalho ou no executável e clique em "Executar como Administrador". Para não ter que fazer isso toda hora, vá nas propriedades do atalho, na aba Compatibilidade e marque a opção "Executar esse programa como administrador.

Quando você executa o Visual Studio 2005 ele recomenda que você faça umas das opções acima. O SQL Server Management Studio Express permite que você entre no programa, mas algumas tarefas , como anexar um novo .mdf e criar uma base de dados, requerem a permissão de administrador.

terça-feira, 10 de abril de 2007

Tratamento de erros: Objeto Exception parte 2

No post anterior sobre exceções, falei sobre o objeto Exception e como utilizá-lo para obter informações sobre erros ocorridos no sistema.


Agora falarei um pouco mais sobre esse objeto, explicando como pode ser utilizado para obter informações específicas a determinados tipos de erro e explicarei um pouco mais sobre a estrutura e funcionamento do bloco try..catch.

O object Exception é , na verdade, a classe base para os objetos que são gerados em caso de erro. Para cada tipo de erro, haverá um objeto diferente, herdando de exception. Esse objeto, dependendo do erro, pode disponibilizar informações adicionais sobre o erro. Se o programa efetuar uma divisão por zero, por exemplo, a exceção DivideByZeroException será gerada. Se for um erro ao executar um comando em um banco SQL Server, você obterá uma SQLException. Essas exceções herdam do objeto Exception, e por isso, possuem todas suas características. Alguns até adicionam informações extras. Quando você executa uma procedure no SQLServer, por exemplo, vários erros podem ocorrer durante a execução. Com o SQLException é possível acessar uma lista desses erros, incluindo informações como a severidade do erro.

Para tratar um erro, como mostrei no último post, você usa a seguinte estrutura :

try
{
// Código a ser tratado
}
catch(Exception ex)
{
// Código que irá tratar o erro.
}

Nesse exemplo, todo tipo de erro será capturado no mesmo bloco. Você pode, porém, criar blocos separados para cada tipo de erro, dessa forma:

try
{
// Código que pode gerar o erro
}
catch(SQLException ex)
{
// Código para tratar erros do SQL Server
}
catch(DivideByZeroException ex)
{
// Código para tratar erros de divisão por zero
}
catch(ArithmeticException ex)
{
// Código para tratar outros erros aritméticos.
}
catch(Exception ex)
{
// Código para tratar outros tipos de erro.
}
finally
{
// bloco que será executado dando ou não erro.
}

No bloco acima, trato vários tipos de erro. Quando um erro ocorre, ele é direcionado para o primeiro bloco catch que atenda a esse erro. É importante lembrar que um bloco Catch com uma determinada exceção, atende a esse exceção e a todas as exceções que herdarem dessas. Por isso, é importante que a ordem dos blocos a ser mantida seja do mais específico para o mais genérico. Se o Catch(Exception ex) estive no início , iria capturar todas as exceções (pois todas elas são exception, ou herdam de Exception), e nenhum dos outros blocos seria executado.

O bloco Finally será sempre executado, idependente de acontecer ou não um erro.

O Fluxo da execução ao acontecer um erro será:
  • Será executado apenas o primeiro bloco catch que atenda a exceção lançada, ou que atenda a umas das classes da hierarquia da qual a exceção herda.
  • O bloco finally será executado, caso haja um.
  • Se algum dos blocos catch atender à exceção, o erro será considerado tratado, e execução continuará do ponto após todo o bloco try..catch.
  • Se não houve um bloco catch que atendesse à exceção, a execução do método atual será interrompida, e o erro será lançado para o bloco try..catch acima, ou para o método que chamou. (Se houver um bloco finally, ele será chamado de qualquer forma).
Quando você escreve um bloco catch para tratar um erro, o erro será considerado tratado ali e após o bloco try..catch a execução continuará normalmente. Se você quiser tratar o erro, mas quiser que o erro ainda seja lançado para o método chamador, pode usar o comando throw, dentro do bloco try..catch.

try
{
// Comandos
}
catch (Exception Ex)
{
// Trata o erro
throw; // Repassa o erro
}

Porém, só faça isso se for fazer alguma coisa com o erro. Se for simplesmente repassar, como abaixo:

try
{
// Comandos
}
catch(Exception ex)
{
throw;
}

Isso não terá a menor funcionalidade, pois esse já é o comportamento padrão. E evite , acima de tudo :) , tratamentos que simplesmente ignorem o erro:

try
{
// Comandos
}
catch(Exception ex)
{}


Isso seria o equivalente a solucionar o problema daquele barulhinho estranho no seu carro com um tapa ouvidos. Você não perceberia mais o problema, mas ele estaria lá, e uma hora a coisa vai complicar.

sábado, 7 de abril de 2007

[Vista] Asp Tradicional: "Caminho Pai Não Permitido"

Uma mensagem que pode aparecer ao tentar executar uma aplicação ASP tradicional no Windows Vista : "Caminho Pai Não Permitido". Parece que por padrão, o ISS7 não permite que se use os dois pontos (..) para referenciar diretórios, como em Response.Redirect("..\clientes\cadastro.asp").

Para corrigir, ou você muda a referência ao diretório para não usar caminhos relativos, ou habilita esse tipo de referência no ISS:
  • Vá no administrador do ISS.
  • Selecione seu site ou diretório virtual
  • Clique em ASP.
  • Mude a configuração "Habilitar caminhos pai" para True.

quarta-feira, 4 de abril de 2007

Tratamento de erros: Objeto Exception parte 1

Vou explicar nesse e nos próximos artigos como funciona o tratamento de erros em aplicações .Net. Vou explicar o funcionamento do tratamento estruturado de exceções, o objeto Exception e como criar suas próprias exceções.

O .Net adotou o modelo de tratamento de erros estruturado, através de objetos representando os erros ocorridos, já utilizado em outras linguagens orientadas a objeto, como Delphi e Java.

Nesse primeiro artigo vou explicar o objeto Exception e como utilizá-lo para obter as informações necessárias a respeito do Erro. Nos próximos artigos tratarei outros aspectos do tratamento de erros, como a propagação do erro na hierarquia de chamada (se não entendeu, tudo bem, vou explicar depois) e a criação de suas próprias exceções.

Para capturar o erro de um código, coloque o código que deseja tratar dentro de uma estrutura try..catch, como mostrado no exemplo abaixo:

try
{
// Código que pode gerar o erro
}
catch(Exception ex)
{
// Aqui você pode tratar o erro com o objeto ex
MostrarMensagem(ex.Message);
}

No exemplo acima, se ocorrer algum erro entre o try e o catch, esse erro será tratado no bloco catch. Note que a propriedade Message do objeto ex é acessada para obter a mensagem de erro. Existem outras propriedades no objeto Exception que podem ajudar na correção do erro. Cito aqui as mais importantes:

Message
A mesma mensagem de erro que é exibida quando o erro não é tratado.

Source
A Fonte do Erro. Normalmente indica a biblioteca ou componente que gerou o erro.

StackTrace
Mostra a pilha de chamadas até o local do erro. É muito útil para encontrar o local do erro. Vai conter um texto com várias linhas como o texto abaixo:

at System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info)
at System.Int32.Parse(String s, NumberStyles style, IFormatProvider provider)
at System.Int32.Parse(String s) at System.Convert.ToInt32(String value)
at MyApp.Form1.btn1_Click(Object sender, EventArgs e)
in C:\Projetos\form1.cs:line 194
(São 4 linhas , a última quebrou por causa do tamanho disponível no blog).

A melhor maneira de ler essa lista é do fim para o início. No exemplo acima, você consegue indentificar que o processo começou no evento onclick do botão btn1 que, por sua vez, chamou, na linha 194 o método System.Convert.ToInt32, que chamou o System.Int32.Parse e assim por diante.

Capturando o erro, você poderia tratá-lo de uma maneira mais adequada, por exemplo, mostrando uma mensagem padrão para o usuário e gravando em um arquivo de log a mensagem de erro real e o StackTrace.

No próximo post irei falar mais do objeto Exception, explicando a estrutura de herança e como obter informações mais detalhadas sobre certos tipos de erro.