Pet Shop 4.0

Para aqueles que conhecem a versão 3.0 desta aplicação exemplo que a Microsoft fez, mostrando as melhores práticas de desenvolvimento utilizando .NET Framework 1.1, eis aqui a nova versão do projeto, a versão 4.0, já agora focado na versão 2.0.

Neste artigo que mostra a versão 4.0, existe uma tabela que compara a quantidade de linhas entre as aplicações e, podem ver lá que a aplicação 4.0 tem bem menos código em relação a versão anterior. Isso tudo, já contando com as novas features do .NET 2.0 e ASP.NET 2.0, quais enumero abaixo (foram extraídas do artigo):

  1. System.Transactions ao invés de ServicedComponent.
  2. Generics para coleções tipadas ao invés de IList (CollectionBase).
  3. ASP.NET Membership e um customizado para Oracle.
  4. Profile Providers para gerenciamento de estado.
  5. Master Pages ao invés de User Controls
  6. ASP.NET Wizard Control.
  7. SqlCacheDependency.
  8. Processamento assíncrono de pedidos – Message Queue.

O download pode ser conseguido aqui.

Encriptando seções do Web.Config

No ASP.NET 2.0, temos uma nova versão do utilitário de linha de comando aspnet_regiis.exe. Consequentemente temos novas funcionalidades adicionadas a ele e, uma delas, é a possibilidade de encriptarmos seções do arquivo Web.Config de uma determinada aplicação ASP.NET. A sua sintaxe para uso é simples:

C:>aspnet_regiis -prov DataProtectionConfigurationProvider -pef appSettings C:WebSite1

A seguir a explicação dos parametros:

-prov: indica o provider que quer utilizar para encriptar a seção.
-pef + seção + diretório físico: indica a seção do arquivo Web.Config que será encriptada, fornecendo em seguida, o caminho físico do diretório da aplicação.

Nullable Types e Base de Dados

Sinceramente imaginei que as coisas seriam mais fáceis quando se trabalha com Nullable Types e base de dados. Hoje estou fazendo alguns testes para entender o comportamento desta nova feature do .NET Framework 2.0. Independente de qualquer coisa que venho a dizer, é de qualquer forma bem legal trabalhar com eles, mas infelizmente quando fui testar a principal utilização do mesmo ao meu ver, que é em conjunto com uma base de dados, fui surpreendido! Explico:

Imaginei eu que poderia fazer algo como:

Dim dr As SqlDataReader = cmd.ExecuteReader()
‘…
Dim dataCompra As Nullable(Of DateTime) = dr.GetDateTime(0)
‘…
If Not dataCompra.HasValue Then MessageBox.Show(“Valor Nulo.”)

Isso seria o ideal ao meu ver, mas quando tentei rodar, me deparei com a seguinte Exception (para minha decepção): System.Data.SqlTypes.SqlNullValueException: Data is Null. This method or property cannot be called on Null values.

Se dermos uma procurada dentro do Reflector pelo método GetDateTime do SqlDataReader, chegamos à função chamada ThrowIfNull(), que atira a exception acima, caso o campo da base de dados que estamos tentando acessar for nulo:

Private Sub ThrowIfNull()
      If Me.IsNull Then
            Throw New SqlNullValueException
      End If
End Sub

Depois disso, resolvi procurar algo no Google a respeito e me deparei com estes dois posts que abordam exatamente isso, ou seja, pelo que entendi, não podemos acessar diretamente os valores nulos da base de dados e atribuirmos aos CLR Nullables Types, sendo necessário uma verificação antes, ficando o código dessa forma:

Dim dr As SqlDataReader = cmd.ExecuteReader()
‘…
Dim dataCompra As Nullable(Of DateTime)
If (Not dr.IsDBNull(0)) Then dataCompra = dr.GetDateTime(0)
‘…
If Not dataCompra.HasValue Then MessageBox.Show(“Valor Nulo.”)

E para piorar, nem o “operador” IIf (no caso do VB.NET) não pode ser utilizado por problemas já reportados anteriormente aqui. A questão é que, se eu tranformar a minha variável dataCompra em um tipo SqlDateTime (tipo que está contido dentro do Namespace System.Data.SqlTypes), eu consigo chegar ao resultado esperado sem problemas:

Dim dr As SqlDataReader = cmd.ExecuteReader()
Dim dataCompra As SqlTypes.SqlDateTime = dr.GetSqlDateTime(0)
If dataCompra.IsNull Then MessageBox.Show(“Valor Nulo.”)

O problema que vejo nisso, é quando vamos atribuir o result-set em um objeto de negócio que temos – quais sempre criamos as suas propriedades com tipos do CLR e não tipos específicos de uma base de dados qualquer – irá obrigar-nos antes de atribuir o valor à mesma, verificar antes se é ou não nulo.

Enviando E-mails com .NET Framework 2.0

Como já mencionei anteriormente nestes links, a forma e opções de envio mudaram bastante no .NET Framework 2.0. Uma das novas funcionalidades, quais não mencionei nos posts anteriores, é utilizar o arquivo *.config da aplicação para definir algumas propriedades essenciais para o envio de e-mails, tais como: Host (endereço do servidor de SMTP), Porta e Credenciais.

Para possibilitar isso, a Microsoft adicionou novos elementos no arquivo *.config da aplicação, sendo eles: system.net, mailsettings, smtp e network. Claro que, nas versões do .NET 1.x, poderíamos definir uma key no arquivo *.config para não deixarmos estes valores (que mudam constantemente, como o endereço do servidor de SMTP) em hard-code. Esses novos elementos poupam-nos de escrever essas keys no appSettings da aplicação e, conseqüentemente, funções e/ou propriedades para recuperarmos isso. Para exemplificar a nova possibilidade de configuração no .NET Framework 2.0, vejamos o exemplo abaixo:

[ *.config ]
<configuration>
  <system.net>
    <mailSettings>
      <smtp deliveryMethod=”network”>
        <network host=”localhost” port=”25″ defaultCredentials=”true” />
      </smtp>
    </mailSettings>
  </system.net>
</configuration>

[ C# ]
using System.Net.Mail;
//…
MailMessage msg = new MailMessage(“israel @ projetando.net”, “israel @ projetando.net”);
msg.Subject = “Teste”;
msg.Body = “Corpo da Mensagem”;
new SmtpClient().Send(msg);

Pode-se ver que ficou muito mais simplificado, pois quando a aplicação corre, o runtime se encarrega de ir até o arquivo de configuração e recuperar os dados necessários para enviar o email. Mas vale lembrar que, a classe SmtpClient suporta em seu construtor (ou através de suas propriedades), que voce defina estes valores via código.

Agora também faz muito mais sentido ter o namespace Mail dentro do System.Net, pois nas versões anteriores, se estivéssemos em um projeto do tipo Console, ou mesmo Windows Forms, tínhamos que fazer referencia à DLL System.Web.dll se quiséssemos enviar e-mails.

E & C no C#?

Bem, navegando pelo portal do MSDN.com, encontrei algo que me chamou a atenção na seção do Visual C#. Neste link pude ver que o Visual C# também terá Edit and Continue, uma “feature” bastante interessante que ajuda na depuração dos aplicativos.

Imaginei que esta “feature” fosse somente implementada no Visual Basic .NET (versão 2005), já que o VB6 a tinha, e pelo que pude ver, os desenvolvedores de Visual C# também poderão desfrutar do E & C. 🙂

Embutindo Imagens no envio de Emails

Finalmente a versão 2.0 do .NET Framework já traz intrinsicamente um recurso que nas versões anteriores somente conseguíamos com a utilização de componentes de terceiros; trata-se da opção de agora podermos embutir dentro do email imagens que farão parte do conteúdo do mesmo.

Nas versões anteriores, se não quiséssemos utilizar componentes de terceiros, tínhamos que disponibilizar em algum lugar, geralmente imagens, que iriam fazer parte do conteúdo do email e, através do acesso via HTTP, a exibíamos. O ponto negativo disso é que depende de uma conexão ativa com a internet para que o usuário consiga visualizar essas imagens.

Felizmente na versão 2.0, temos duas principais classes para trabalharmos com isso. São elas: AlternateView e LinkedResource. A primeira especifica diferentes cópias do conteúdo do email, ou seja, voce define o email com o formato e tags HTML e, se o leitor de emails do destinatário não suportar HTML, voce pode fornecer através desta classe, uma versão em Plain Text do mesmo conteúdo. Já a segunda classe, representa um recurso externo que será embutido dentro do conteúdo do email que, na maioria dos casos, é uma imagem. Depois desta classe criada, o adicionamos na coleção de LinkedResources do objeto AlternateView.

O código abaixo mostra-nos como devemos proceder para conseguirmos enviar um email com uma imagem embutida no corpo do mesmo:

     using System.Net.Mail;
     using System.Net.Mime;

     MailMessage mail = new MailMessage(“israel@projetando.net“, “israel@projetando.net“);
     mail.Subject = “Testando Imagens Embutidas”;
     string body = @”<img src=””cid:Imagem1″” /><br><br>Embutindo Imagens no Email.”;

     AlternateView view = 
          AlternateView.CreateAlternateViewFromString(body, null, MediaTypeNames.Text.Html);

     LinkedResource resource = new LinkedResource(Server.MapPath(“Logo.gif”));
     resource.ContentId = “Imagem1”;
     view.LinkedResources.Add(resource);

     mail.AlternateViews.Add(view);
     mail.IsBodyHtml = true;
     new SmtpClient(“mail.servidor.com.br”).Send(mail);

Como podemos analisar no código acima, criamos uma classe do tipo MailMessage, como já fazíamos nas versões anteriores. Dentro do conteúdo do email (body), definimos a tag img e o atributo src que corresponderá a imagem no local que desejarmos. Através do cdi especificamos que o conteúdo será “substituído” pelo conteúdo que mais tarde vamos vir a embutir. Através do método CreateAlternateViewFromString, onde passamos o corpo da mensagem e o tipo que ela irá ser (no caso HTML), devolvemos uma instancia da classe AlternateView baseada nesses mesmos parametros.

Depois disso, criamos um objeto do tipo LinkedResource, onde vamos definir a imagem (ou recurso) que vamos embutir. É importante dizer que a propriedade ContentId deve ser exatamente o mesmo ID que definimos no cid do corpo da mensagem. Agora basta adicionarmos o objeto na coleção de LinkedResources do objeto AlternateView e, este por sua vez, adicionamos na coleção de Views do objeto MailMessage.

Finalmente, através de uma instancia do objeto SmtpClient, utilizamos o método Send para enviar o email. A Imagem abaixo mostra o email já dentro do Microsoft Outlook. Reparem que a imagem é embutida no local que definimos dentro do código HTML do corpo da mensagem e que também que não existem arquivos anexados ao email.

Exceptions de Aplicações

Via Rockford Lhotka encontrei um link interessante para um site chamado ExceptionCollection.com, qual trata-se de um serviço free para desenvolvedores, onde é fornecido uma espécie de repositório das Exceções que são atiradas e consequentemente apanhadas dentro da nossa aplicação.

Depois de efetuado o cadastro, voce pode se logar neste site e, verificar as Exceções que suas aplicações possivelmente possam ter gerado. Para poder enviar a Exception para o repositório, o código fica semelhante ao mostrado abaixo:

     catch (Exception objException)
     {
          Sherpa.ExceptionReport objExceptionReport;
          objExceptionReport = new Sherpa.ExceptionReport(“login”, objException)

          if(!objExceptionReport.Send())
          {
               // LOG objExceptionReport.ErrorMessageFromFailedSend (OPTIONAL)
          }
     }

Isso tudo é feito/logado através de um WebService ou mesmo fazendo a referencia a uma DLL fornecida pelo próprio site, qual pode ser visto/testado neste link. Para maiores detalhes técnicos do projeto, por favor visite o seguinte endereço: http://www.exceptioncollection.com/instructions.aspx.

Inserindo Datas no SQL Server

Umas preocupações que mais vejo quando alguém quer incluir datas em uma coluna do tipo DateTime no banco de dados SQL Server 2000 é saber qual o formato enviar. Já vi muitos casos onde o pessoal faz algo do tipo:

     Dim d As DateTime = DateTime.Now
     Dim query As String = “INSERT INTO Tabela VALUES(‘” & d.ToString(“MM/dd/yyyy”) & “‘)”

Eu particularmente também já tive essa dúvida e ao procurar saber, o segredo está em não espeficar um formato como é feito acima, deixando o SqlParameter/SqlCommand se encarregar de fazer essa trabalho por nós. Para consertar o código acima, fazendo da forma correta, temos que criar os devidos parametros para o campo (não somente do tipo data, mas qualquer um) e executar a query. Abaixo o exemplo:

     Dim cmd As New SqlCommand(“INSERT INTO Tabela VALUES(@Data)”, conn)

     Dim data As New SqlParameter(“@Data”, SqlDbType.DateTime)
     data.Value = DateTime.Now
     cmd.Parameters.Add(data)
     ‘….
     cmd.ExecuteNonQuery()