APIs obsoletas – ASP.NET 2.0

Com a vinda do novo ASP.NET, o 2.0, muitas coisas que existiam nas versões 1.x acabaram ficando obsoletas, sendo uma delas, a velha conhecida de todos nós, a propriedade SmartNavigation dos WebForms. Ela tem a responsabilidade de manter a posição (scroll) da página quando um PostBack é causado na mesma.

Lendo a listagem de APIs obsoletas do .NET Framework 2.0 Beta 2, vi que a propriedade SmartNavigation foi substituída pela propriedade MaintainScrollPositionOnPostBack da classe Page.

Além disso, a Namespace Mail foi “transportado” para o Namespace System.Net.Mail. Uma outra que sofreu uma grande alteração foram os métodos da classe Page que utilizávamos para trabalhar com código Javascript no cliente (i.e. o método RegisterClientScriptBlock) que agora estão todas dentro de uma classe chamada ClientScriptManager e a classe Page, por sua vez, à expõe através de uma propriedade chamada ClientScript.

Para uma lista completa de todas as APIs obsoletas no .NET Framework 2.0, aconselho a baixar aqui, diretamente da Microsoft e analisar.

Analisando o Microsoft PetShop 3.0

Para quem não conhece, o Microsoft PetShop 3.0 é uma aplicação de uma loja virtual fictícia que vende pequenos animais que a Microsoft construiu com o propósito de um caso de estudo baseado no Java Pet Store da Sun, mas construindo-a sob a Plataforma .NET. Mas este artigo não tem o intuito de mostrar esta comparação e sim abordar a estrutura em que o mesmo foi construído. Para quem se interessar, poderar ver o estudo/análise desta comparação através deste link: http://www.middleware-company.com/buzz/buzz0703.jsp.

Microsoft PetShop 3.0 é uma aplicação Web, construída em ASP.NET, que comunica com componentes de negócios escritos em C#, quais compõem a Camada de Negócios (Business Logic Layer). ADO.NET é utilizado para acessar as Base de Dados, acesso qual está abstraído em uma camada de acesso a dados (Data Access Layer (DAL)), separando-se da camada de negócios.

Figura 1 – Microsoft PetShop 3.0.

Estrutura da Solução

Como podemos ver abaixo na Figura 2, a solução da Aplicação e constituída de diversos projetos, sendo 1 projeto do tipo WebApplication (User Interface), 8 projetos do tipo Class Library e 2 projetos “Build” para efetuar algumas configurações no ato da instalação. Veremos abaixo, a descrição de cada um deles.

Figura 2 – Estrutura da Solução.

 

Projeto Finalidade
BLL Contém as regras do negócio da aplicação.
ConfigTool Utilizado para Encriptar/Descriptar ConnectionString e fazer entradas no Event Log.
DALFactory Classe que determina qual Database será utilizada.
IDAL Interfaces que deverão ser implementadas para cada DAL.
Model Classes de dados ou objetos de negócio.
OracleDAL Implementação específica para acesso a fonte de dados Oracle.
Post-Build Responsável por adicionar os Assemblies no GAC e COM+.
Pre-Build Remove Assemblies do GAC e COM+.
SQLServerDAL Implementação específica para acesso a fonte de dados SQL Server 2000.
Utility Classes utilitárias.
Solution Items StrongKey para assinar os Assemblies.

Aplicação Distribuída

Para que a solução atenda o cenário de uma aplicação distrubuída, são criados duas Base de Dados (MSPetShop e MSPetShopOrders). Em uma delas, são armazenadas as informações referentes aos Produtos, Clientes, Banners, entre outros. Já na segunda Base de Dados, são armazenados os pedidos dos clientes e seus repectivos Items. Veremos abaixo a finalidade de cada uma das tabelas:

Tabela Descrição
Account Informações sobre o Cliente.
BannerData Armazena informações sobre Banners.
Category Categorias dos Produtos.
Inventory Estoque dos Produtos.
Item Detalhes dos Produtos.
LineItem Detalhes dos Items dos Pedidos.
Orders Pedidos realizados por um determinado Cliente.
OrderStatus Status do Pedido.
Product Catalogo dos Produtos.
Profile Perfil do Cliente.
Signon Login dos Usuários.
Supplier Informações dos Fornecedores.

OBS.: As linhas que estão com o fundo cinza, pertencem a Base de Dados “MSPetShopOrders”.

Arquitetura

Figura 3 – Arquitetura da Solução.

Como vemos na figura acima, a aplicação está dividida em três grandes camadas: Camada de Apresentação, Camada de Negócios e Camada de Acesso a Dados. O COM+ entra no jogo para garantir a integridade dos pedidos, ou seja, quando efetuamos uma compra, se algo falhar durante a transação, o mesmo será desfeito, mantendo assim a integridade dos dados.

Os componentes de negócios fazem as devidas manipulações para serem exibidas no Front-End, mas tudo começa a ficar interessante a partir daqui.

A idéia é de deixar a aplicação independente de Base de Dados. Isso não seria tão difícil, pois poderíamos utilizar OleDb para acessar qualquer uma das Bases de Dados, criando assim uma única classe genérica de acesso. Mas isso torna a aplicação pouco performática, pois não utiliza os Providers específicos para cada Base de Dados. Um dos requirementos ao construir esta aplicação era justamente obter alta performance, e em virtude disso, é indiscutível o uso dos Providers nativos: SqlClient e OracleClient.

Com essa meta, uma forma de simplicar o acesso aos dados, foi utilizar a Pattern Abstract Factory [Gof], juntamente com Reflection que cria e instancia o objeto correto em runtime. É criado uma Interface genérica, que contém os métodos necessários que deve ser implementada em cada classe de acesso a dados. Para cada classe de acesso a dados, você deve implementar esta Interface, utilizando as classes e o Provider específico para o Banco de Dados que está sendo requisitado.

Depois das classes de acesso a dados de Bases diferentes, cria-se uma Factory, que em runtime, utilizando Reflection, vai identificar qual das classes de acesso a dados irá instanciar, baseando-se em uma chave definida no arquivo Web.Config da aplicação Web. A figura abaixo, ilustra o processo:

Figura 4 – Escolhendo qual DB utilizar.

Se algum dia tivermos a necessidade de que a aplicação atenda a mais um tipo diferente de Base de Dados, por exemplo Microsoft Access, teríamos que seguir o seguinte procedimento:

1 – Criar classes de acesso a dados, utilizando OleDb e nela implementar as Interfaces IDAL;

2 – Compilar estas novas classes e fazer Deploy para o servidor;

3 – Alterar a configuração no arquivo Web.Config para chamá-la.

DAO – Data Access Objects

Data Access Objects ou DAO, é um padrão de projeto que é utilizado para abstrair o acesso a dados da camada de negócios (Business Layer), que por sua vez, acessa a Base de Dados através de Data Access Objects, tornando assim transparente o acesso. A DAO é uma DAL específica para um determinado objeto, fazendo com que a camada de negócios fique sem conhecimento da Base de Dados, pois isto está tudo encapsulado.

Esta abstração encapsula a implementação utilizada para acesso, gravação, gerenciamento da conexão referente a fonte de dados, que realmente não interessa a Business Layer qual o tipo de armazenamento de dados está sendo utilizado.

Figura 5 – Diagrama de Classe da Pattern DAO.

Abstract Factory

Abstract Factory fornece uma Interface ou Classe Abstrata para criar uma família de objetos relacionados dependentes sem especificar a classe concreta. Sendo assim, no projeto PetShop 3.0, é criado uma Interface chamada IDAL, que contém os métodos de manipulação de dados, qual é implementada em todas as classes concretas para accesso à diferentes Base de Dados.

Com isso, ao invés do Cliente instanciar a classe concreta, chama-se método de criação (Factory Method), que invoca a Abstract Factory, e utiliza este objeto para chamar os métodos e/ou propriedades da classe concreta. Ganhamos bastante flexibilidade, pois baseado em uma Key (no caso, chamada de WebDAL) dentro do arquivo Web.Config, em runtime ele saberá qual dos objetos concretos deverá instanciar.

Traduzindo em Código

Para que as coisas fiquem um pouco mais claras, veremos abaixo, como é feito isso. Sabendo que temos que implementar as Interfaces contidas na IDAL, veremos uma delas (Account):

1
2
3
4
5
6
7
 
public interface IAccount
{
    AccountInfo SignIn(string userId, string password);
    AddressInfo GetAddress(string userId);
    void Insert(AccountInfo account);
    void Update(AccountInfo account);
}
 
Código 1 – Interface IAccount.

Na camada de acesso a dados, deve-se implementar esta interface (IAccount) e codificar utilizando o Provider específico para aquela Base de Dados. No caso do PetShop, a implementação foi realizada utilizando o DAAB (Data Access Application Block) que utiliza SqlClient e também implementando para acesso a Base de Dados Oracle, utilizando OracleClient.

1
2
3
4
 
public class Account : IAccount
{
    //…
}
 
Código 2 – Implementado Interface IAccount.

Feito isso, a Factory se encarrega de verificar qual dos objetos instanciar, verificando no Web.Config qual a Base de Dados a ser utilizada, e através de Reflection, carrega a cria a instância da mesma através do Factory Method:

1
2
3
4
5
6
7
8
9
10
 
public class Account
{
    public static PetShop.IDAL.IAccount Create()
    {
        string path = System.Configuration.ConfigurationSettings.AppSettings[“WebDAL”];
        string className = path + “.Account”;
 
        return (PetShop.IDAL.IAccount) Assembly.Load(path).CreateInstance(className);
    }
}
 
Código 3 – Factory Method.

E finalmente em nossa camada de negócios, utilizamos nossa Factory para que ela gere a instância correta da classe de acesso e manipulação da Base de Dados a ser utilizada no Projeto:

1
2
3
4
5
6
7
8
9
10
11
 
public class Account
{
    public void Update(AccountInfo account)
    {
        if (account.UserId.Trim() == string.Empty)
            return;
        
        IAccount dal = PetShop.DALFactory.Account.Create();
        dal.Update(account);
    }
}
 
Código 4 – “Chamando” o Factory Method na Camada de Negócios.

Conclusão: Como vimos a utilização da Orientação à Objetos no Design de nossas aplicações, nos traz grande produtividade e facilidade em uma posterior manutenção. No caso do PetShop que vimos acima, é um ótimo exemplo, onde precisamos gerar independência de Base de Dados, mas existem vários cenários onde podemos utilizar Abstract Factory e principalmente DAO.

Configurando uma aplicação ASP.NET

Hoje temos dois arquivos bastante importantes quando trabalhamos com aplicações ASP.NET. São eles: Global.asax e o arquivo Web.Config. Esses arquivos tornam a Aplicação bastante flexível, pois reúnem as configurações e eventos em um único lugar.

Com o arquivo Global.asax, você executa um determinado código quando sua Aplicação é iniciada/finalizada ou até mesmo quando qualquer página da Aplicação for requisitada. Já o arquivo Web.Config, armazena as configurações da Aplicação, tais como: Estado de Sessão, Segurança, Globalização, etc.

Quando se trabalha com o Visual Studio .NET, ao criar uma nova Aplicação do tipo WebApplication, automaticamente ele se encarrega de adicioná-los por padrão è ela.

Figura 1 – Os arquivos Global.asax e Web.Config são criados automaticamente.

O fato de termos várias páginas ASP.NET agrupadas você até pode chamar de Aplicativo, mas isso vai muito além. Um Aplicativo ASP.NET tem além de todas as páginas, handlers de evento, módulos e código executável que é executado dentro de um Diretório Virtual no servidor Web (IIS).

O Diretório bin

Dentro da raiz do Aplicativo há um diretório chamado “bin”. Dentro dele são armazenados arquivos em formato binário compilados utilizados por seu Aplicativo (um exemplo são os arquivos com extensão *.dll).

Os assemblies colocados aqui estão automaticamente disponíveis para seus arquivos *.aspx, e com isso não precisamos nos preocupar com os procedimentos complexos de criação.

O Arquivo Global.asax

O Diretório Virtual no IIS é grande parte do Aplicativo ASP.NET. Independente da página, o aplicativo é iniciado na primeira vez que ela é solicitada. Enquanto os usuários navegam pelas páginas, o processamento ocorre em segundo plano para tratar do Aplicativo.

O Aplicativo pode cair e ser reiniciado da mesma forma que qualquer Aplicativo tradicional, com a seguinte excessão: enquanto um Aplicativo tradicional é iniciado e executado em um computador desktop permitindo a interação direta com o usuário, um Aplicativo ASP.NET é iniciado e executado em um servidor Web, e o usuário utiliza um browser para acessá-lo.

Lembrando que tudo em .NET Framework é um objeto, temos um objeto chamado HttpApplication, que nos fornece métodos e eventos. Com isso podemos deduzir que sempre que uma página em seu Diretório Virtual for solicitada pela primeira vez, um objeto do tipo HttpApplication é instanciado.

Como as páginas ASP.NET realizamos uma ou mais tarefas individualmente, elas não controlam o Aplicativo de modo geral, não podendo uma página afetar diretamente a outra. Deve existir uma localização central que controla a execução do Aplicativo. Tendo este cenário, entra em cena o arquivo Global.asax.

Conhecido como Arquivo de Aplicação de ASP.NET, o Global.asax permite-nos programar no lugar do objeto HttpApplication e com isso você poderá controlar o seu Aplicativo ASP.NET como faz com qualquer outro objeto por meio de métodos e eventos.

OBS.: Apesar do Visual Studio .NET incluir o arquivo Global.asax por default, ele é totalmente opcional. Se seu Aplicativo não conter um arquivo desse tipo, o programa opera de forma padrão. Desejando adicionar funcionalidades, a sua utilização torna-se essencial.

O arquivo Global.asax é colocado no Diretório raiz do Aplicativo (Exemplo: http://servidor/site/ – c:inetpubwwwwrootsite). O ASP.NET controla o acesso à esse arquivo, de modo que ele não é acessível através do browser, o que garante a segurança. Se alguém tentar executar a URL: “http://www.site.com.br/global.asax” o receberá a seguinte notificação de erro:

Figura 2 – Acessando o arquivo Global.asax através do browser.

Este arquivo é gerenciado pela .NET Framework. Sempre que ele for modificado, o CLR detecta isso e faz com que o Aplicativo seja reiniciado para que as novas mudanças tenham efeito. Isso pode ocasionar transtornos para os usuários finais. Modifique este arquivo somente o necessário.

Programando o arquivo Global.asax

O arquivo Global.asax opera de maneira semelhante as páginas *.aspx. Você utiliza o Global.asax para sincronizar qualquer evento exposto pela classe HttpApplication. Eventos quais veremos abaixo:

Evento Descrição
AcquireRequestState Acionado quando o Aplicativo obtém o cache para a solicitação.
AuthenticateRequest Acionado quando o Aplicativo tenta autenticar a solicitação de HTTP.
AuthorizeRequest Acionado quando o Aplicativo tenta autorizar a solicitação de HTTP.
BeginRequest Acionado quando a solicitação de HTTP é iniciada.
EndRequest Acionado quando a solicitação de HTTP é concluída.
Error Acionado quando surge um erro.
PostRequestHandlerExecute Acionado imediatamente depois do handler de HTTP processar a solicitação.
PreRequestHandlerExecute Acionado imediatamente antes do handler de HTTP processar a solicitação.
PreSenderRequestContent Se a solicitação tiver conteúdo adicional (QueryString, Variáveis de Formulário, etc.), esse evento é acionado imediatamente antes daquele conteúdo ser recebido.
PreSenderRequestHeaders Acionado imediatamente antes de os cabeçalhos de solicitação serem recebidos.
ReleaseRequestState Acionado quando o Aplicativo libera o estado de sessão para a solicitação.
ResolveRequestCache Acionado quando o Aplicativo determina o cache para a solicitação.
UpdateRequestCache Acionado quando o Aplicativo autaliza e libera o cache para a solicitação.

Abaixo o arquivo Global.asax padrão:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
 
Imports System.Web
Imports System.Web.SessionState
 
Public Class Global
    Inherits System.Web.HttpApplication
 
    Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
        ‘…
    End Sub
 
    Sub Session_Start(ByVal sender As Object, ByVal e As EventArgs)
        ‘…
    End Sub
 
    Sub Application_BeginRequest(ByVal sender As Object, ByVal e As EventArgs)
        ‘…
    End Sub
 
    Sub Application_AuthenticateRequest(ByVal sender As Object, ByVal e As EventArgs)
        ‘…
    End Sub
 
    Sub Application_Error(ByVal sender As Object, ByVal e As EventArgs)
        ‘…
    End Sub
 
    Sub Session_End(ByVal sender As Object, ByVal e As EventArgs)
        ‘…
    End Sub
 
    Sub Application_End(ByVal sender As Object, ByVal e As EventArgs)
        ‘…
    End Sub
 
End Class
 
Código 1 – O arquivo Global.asax.

Repare que na Linha 5 herdamos a classe HttpApplication dentro do Global.asax, como expliquei acima.

O arquivo mostrado no Código 1 esta apenas com o Eventos que o próprio Visual Studio .NET deixa criado. Você ainda poderá trabalhar com os Eventos mostrados na tabela acima, e como vemos na Figura 3, logo abaixo:

Figura 3 – Os Eventos do arquivo Global.asax.

Agora veremos abaixo qual a ordem de execução dos Eventos do arquivo Global.asax:

1.  Application_Start
2.  Application_BeginRequest
3.  Application_AuthenticateRequest
4.  Application_AuthorizeRequest
5.  Application_ResolveRequestCache
6.  Session_Start
7.  Application_AcquireRequestState
8.  Application_PreRequestHandlerExecute
9.  Page_Load (arquivo *.aspx) ou qualquer outra saída de página
10. Application_PostRequestHandlerExecute
11. Application_ReleaseRequestState
12. Application_UpdateRequestCache
13. Application_EndRequest
14. Application_PreSendRequestHeaders

OBS.: Vale lembrar que alguns eventos são executados de acordo com alguma circunstância. Um exemplo disso é o caso do Evento Session_Start, que somente é executado quando qualquer página é solicitada por aquele usuário, a partir da segunda vez/página, o Evento não ocorre novamente.

Configurando a Aplicação ASP.NET

Da mesma forma que é importante controlar o processamento do Aplicativo, é necessário configurá-lo. Controle de Acesso, Segurança, Estado de Sessão e até mesmo configurações personalizadas. Para isso o ASP.NET nos fornece um arquivo baseado em texto, que nos dá extensibilidade e fácil configuração.

Além disso, a configuração é hierárquica, ou seja, as informações de configuração de aplicativos são aplicadas de acordo com a estrutura de Diretórios Virtuais do seu site. Os sub-diretórios podem herdar ou anular opções de configuração de seus diretórios-pai.

Por padrão, todos os diretório são herdados de um arquivo de configuração padrão de sistema chamado de machine.config, (localizado em: “WinNTMicrosoft.NETFrameworkVersãoCONFIG).

O arquivo que é responsável pela configuração é o Web.Config, que é um arquivo XML, qual veremos à seguir.

O Arquivo Web.Config

Dentro deste arquivo não há nada de especial, à não ser que ele contém chaves e valores que são reconhecidos pelo ASP.NET. Tais valores são facilmente modificáveis, e como mencionei anteriormente, você pode adicionar suas próprias chaves, para controlar outras operações que o ASP.NET não faz para você.

A estrutura básica de um arquivo Web.Config é essa:

1
2
3
4
5
6
7
8
9
10
11
 
<configuration>
    <configSections>
 
    </configSections>
    <system.web>
 
    </system.web>
    <system.net>
 
    </system.net>
</configuration>
 
Código 2 – Estrutura básica do arquivo Web.Config.

Como vemos, é somente XML. Entre as tags <configuration> há dois elementos diferentes: handlers de seção de configuração e configurações da seção de configurações.

As configurações que configuram seu Aplicativo são pares de chave/valor. Há dois tipos destas seções: system.net e system.web. A primeira seção é para configurar o tempo de execução da .NET em si, portanto, não se preocupe muito com isso. Já a segunda é para controlar o ASP.NET. Suas configurações serão colocadas nas tags <system.web>.

OBS.: O arquivo Web.Config faz distinção entre letras maiúsculas e minúsculas, e sem o formato correto, seu Aplicativo poderá gerar erros.

Abaixo uma tabela com as configurações disponíveis para a utilização no arquivo Web.Config:

Seção Descrição
<appSettings> Utilizada para armazenar suas próprias configurações personalizadas de Aplicativo.
<authentication> Configura como o ASP.NET autentica seus usuários.
<authorization> Configura a autorização de recursos no ASP.NET.
<browsercaps> Responsável por controlar as configurações do componente de capacidades do navegador.
<compilation> Responsável por todas as configurações de compilação.
<customErrors> Indica como exibir erros no navegador.
<globalization> Responsável por configurar as opções de globalização.
<httpHandlers> Responsável pelo mapeamento de URLs de entrada em classes IHttpHandler.
<httpModules> Responsável por configurar Módulos de HTTP dentro de um aplicativo.
<identity> Controla como o ASP.NET acessa seus recursos.
<location> Controla como as configurações se aplicam a um diretório.
<pages> Controla configurações de páginas.
<processModel> Configura as configurações de modelo de processo do ASP.NET em Sistemas de Servidor da Web do IIS.
<sessionState> Configura o Estado de Sessão.
<trace> Configura o Trace (Rastreamento).
<webServices> Controla as configurações dos Serviços da Web.

Como podem ver, o arquivo Web.Config ajuda a tornar a Aplicação bastante flexível, ou seja, podemos definir funcionalidades globais em um único lugar. Além disso, uma das vantagens é que se houver a necessidade de mudar algo dentro do arquivo Web.Config, não há a necessidade de recompilar a Aplicação.

Com tantas tags e atributos, que podem nos deixar confusos, infelizmente o Visual Studio .NET em suas versões 2002 e 2003 não implementou o Intellisense em arquivos *.config. Mas há uma forma de obtermos de terceiros tal funcionalidade no seguinte endereço:

http://www.radsoftware.com.au/web/CodeZone/Articles/IntellisenseWebConfig.aspx

Conclusão: Vimos que o arquivo Global.asax nos permite controlar quase todos os aspectos do processamento de uma página ASP.NET. Você pode utilizar os Eventos do objeto HttpApplication para realizar operações imperceptíveis para o usuário, tornando sua Aplicação muito mais robusta e eficiente. Além disso podemos tornar a nossa Aplicação bastante flexível utilizando o arquivo de configuração Web.Config, fazendo com que a mesma possa reagir rapidamente à qualquer mudança.

Formatando valores em colunas do DataGrid

Frequentemente quando utilizamos um controle do tipo DataGrid, e inserimos valores do tipo Data, Dinheiro, Inteiros ou Decimais, precisamos formatar esse valor de acordo com a finalidade desse Campo. Nesse artigo apresentarei a propriedade DataFormatString da BoundColumn de um DataGrid.

Existem dois tipos de formatação: Standard Formats e Custom Formats. Como o objetivo do artigo é mostrar as formatações mais utilizadas em aplicativos para serem executados nos padrões brasileiros, então deixarei claro o seguinte: O padrão para valores numéricos será adotado o Stardand Format. Já a formatação para datas, será utilizado o Custom Format.

A propriedade DataFormatString fornece uma formatação customizada para o valor inserido na BoundColumn. Esta propriedade consiste em duas partes separadas por dois pontos estando dentro de um par de chaves da seguinte forma: {:}. Isso é válido apenas quando estiver inserindo na BoundColumn valores numéricos ou do tipo data.

A sintaxe é a seguinte: {0:[Formato][Qtde. Casas Decimais]}. O caracter que vem após os dois pontos, é o formato em que o valor será exibido. Você também poderá optar por definir a quantidade de casas decimais da seguinte forma: {0:C2}. A seguir uma lista com os valores possíveis:

Standard Format Descrição
C Exibe o valor no formato de moeda.
D Exibe o valor em formato decimal.
E Exibe o valor no formato cientìfico (exponencial).
F Exibe o valor no formato fixo.
G Exibe o valor no formato geral.
N Exibe o valor no formato numérico.
P Exibe o valor no formato de porcentagem.
X Exibe o valor no formato hexadecimal.

Observações: Os caracteres acima que especificam o formato a ser exibido não são case-sensitive, exceto para o X, pois se ele for minúsculo, os valores serão apresentados em minúsculo, do contrário, serão exibidos em maiúsculo.

Para configurar os valores no DataGrid, clique com o botão direito do mouse em cima do mesmo, e selecione Property Builder. Em seguida, vá até a aba Columns e ao incluir uma nova BoundColumn, a propriedade DataFormatString será habilitada para que você possa definir a formatação customizada. A imagem abaixo ilustra o processo:

Figura 1 – Configurando a propriedade DataFormatString do DataGrid.

A figura abaixo exibe os valores no DataGrid de acordo com a formatação pré-definida na propriedade DataFormatString.

Figura 2 – Configurando a propriedade DataFormatString do DataGrid.

Aqui chamo a atenção para a coluna onde é exibido o valor no formato moeda e o separador de casas decimais. Como não foi definido nenhuma cultura no arquivo Web.Config, por padrão ele adota as configurações regionais definidas no servidor. Se acrescentar a cultura pt-BR nas configurações de nossa aplicação, verão que os valores passarão a serem exibidos no formato brasileiro. Abaixo a ilustrução deixará claro:

1
 
<globalization requestEncoding=”utf-8″ responseEncoding=”utf-8″ culture=”pt-br” />
 
Código 1 – Alterando a cultura no arquivo Web.Config.

Com essa mudança, agora temos os valores sendo exibidos no padrão brasileiro, conforme mostrado na figura 3:

Figura 3 – Valores sendo exibidos no formato brasileiro.

Além das configurações para valores numéricos, ainda podemos utilizar a propriedade DataFormatString para formatarmos datas que são inseridas no DataGrid. Abaixo uma tabela as as possibilidades de formatação para datas:

Custom Format Descrição
MM/dd/yyyy Formato Mês/Dia/Ano
dd/MM/yyyy Formato Dia/Mês/Ano
hh:mm Formato Hora:Minuto
hh:mm:ss Formato Hora:Minuto:Segundo
dd/MM/yyyy hh:mm:ss Formato Dia/Mês/Ano Hora:Minuto:Segundo

OBSERVAÇÕES: Devemos nos atentarmos para o MM e para o mm, pois maiúsculo significa Mês, já o minúsculo significa Minutos.

Há ainda vários outros padrões para a formatação de datas, quais não optei por colocar aqui por que utilizamos na maioria das vezes o formato brasileiro. Mas para quem se interessar pode encontrar maiores informações no link direto da fonte da Microsoft: Standard DateTime Format Strings.

Como dito anteriormente, a configuração da formatação para data, funciona da mesma forma que a formatação para valores numéricos, ou seja, você define na propriedade DataFormatString da BoundColumn do DataGrid, como por exemplo: {0:dd/MM/yyyy hh:mm:ss}. A Figura 4 ilustra os possíveis formatos para datas:

Figura 4 – Formatando Datas.

IMPORTANTE: Você poderia também ao invés de barras “/” utilizar o hífen “-” como separador para as Datas, ficando a String de formatação da seguinte forma: {0:dd-MM-yyyy hh:mm:ss}.

Poderá também fazer a formatação diretamente no HTML, utilizando a propriedade DataItem em conjunto com a método Format. Exemplo:

1
2
3
 
<asp:TemplateColumn>
    <%# String.Format(“{0:c}”, Convert.ToInt32(Container.DataItem(“NomeDaColuna”))) %>
</asp:TemplateColumn>
 
Código 2 – Formatando valores diretamente no código HTML.

CONCLUSÃO: Com este artigo mostrei as possíveis formas de formatação para valores do tipo numéricos de datas que são inseridos nas BoundColumns do DataGrid. Aconselho a darem uma olhada também no link que coloquei um pouco mais acima que diz respeito à outros tipos de formatação bastante utilizados pelas aplicações.

FormatandoValores.zip (19.08 kb)

Construindo uma Área Restrita

Sempre que construímos uma aplicação Web, é muito comum criarmos áreas administrativas e restritas, onde os usuários poderão gerenciar o conteúdo das páginas, pedidos, clientes, entre muitas outras coisas. Neste artigo explicarei como fazermos para criarmos uma área restrita em sua aplicação.

Devemos criar uma aplicação ASP.NET no Visual Studio. Inicialmente, criaremos uma pasta chamada “Administracao” onde ficaram contidas as páginas restritas. Dentro dela uma página “Default.aspx” e fora dela, devemos ter outro WebForm que será responsável para que usuário faça o Login. Esta página chamará “Login.aspx”. A estrutura de arquivos de nosso projeto ficará algo como:

Figura 1 – Estrutura de Arquivos da Aplicação.

Depois disso, devemos informar qual será a página de “Start”. Para isso informaremos que a página inicial será a “Default.aspx”, dentro da pasta “Administracao”. Explico: Quando a aplicação é iniciada, a página “Default.aspx” será chamada, ao chamá-la será verificado se o usuário corrente encontra-se ou não logado. Caso não esteja, ele será redirecionado para a página “Login.aspx”, onde ele será obrigado à se autenticar.

Figura 2 – Definindo a página inicial.

Bem, antes de mais nada, devemos construir a página “Login.aspx”, onde devemos ter o formulário para que o usuário possa digitar seu Login e Senha para se identificar. O formulário ficará da seguinte forma:

Figura 3 – Página de Login.

Em primeiro lugar, quando iniciamos a aplicação, reparem que ele requisitou a página “Default.aspx” dentro do diretório “Administracao”. Como foi verificado que o Usuário não está logado, fui direcionado para a página de Login (“Login.aspx”) e anexado na URL uma QueryString chamada “ReturnURL”, que será a página que o usuário será redirecionado após efetuar a Login (caso seja válido). Outro ponto que gostaria de chamar a atenção é para o CheckBox “Lembrar”. Ele serve para definirmos se o Cookie será ou não persistente, ou seja, se quando o usuário fechar o Browser e abri-lo novamente, já ficará ou não autenticado.

Antes de codificarmos o evento Click do botão de Login, vamos ver as configurações que devemos fazer no arquivo Web.Config:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 
<?xml version=“1.0” encoding=”utf-8″ ?>
<configuration>
    <system.web>
        <authentication mode=”Forms”>
            <forms name=”Administracao” loginUrl=“Login.aspx” />
        </authentication>
    </system.web>
    <location path=”Administracao”>
        <system.web>
            <authorization>
                <deny users=”?” />
            </authorization>
        </system.web>
    </location>
</configuration>
 
Código 1 – Configurações no arquivo Web.Config.

Informamos no arquivo Web.Config a página que será efetuado o Login e também informamos que a pasta “Administração” será restrita. A partir disso o usuário deverá efetuar o Login antes de visualizar o conteúdo da pasta “Administracao”.

Agora vamos criar uma tabela no SQL Server chamada “Administradores” onde armazenará o cadastro dos Administradores do Sistema. Depois de criada, no evento Click do Botão de Login, devemos ir até o SQL Server e verificar se esse usuário existe na Base de Dados. Caso positivo, ele será redirecionado para a página que encontra-se na QueryString “ReturnURL”, caso contrário, não podemos permitir o acesso.

A Tabela Administradores terá apenas o seguintes campos: Nome (Varchar(50)), Login(Varchar(10)) e Senha(Varchar(6)). E o evento Click ficará da seguinte forma:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
 
Imports System.Web.Security
Imports System.Data.SqlClient
 
Private Sub btnLogin_Click(ByVal sender As System.Object, _
    ByVal e As System.EventArgs) Handles btnLogin.Click
 
    Dim conn As SqlConnection = New SqlConnection(“CONNECTION_STRING”)
    Dim strQuery As String
    Dim strRetorno As String
    strQuery = “SELECT Nome FROM Administradores “
    strQuery &= “WHERE Login = @Login AND Senha = @Senha”
    Dim cmd As SqlCommand = New SqlCommand(strQuery, conn)
 
    Dim Login As SqlParameter = New SqlParameter(“@Login”, SqlDbType.VarChar, 10)
    Login.Value = Me.txtLogin.Text.Trim
    cmd.Parameters.Add(Login)
 
    Dim Senha As SqlParameter = New SqlParameter(“@Senha”, SqlDbType.VarChar, 6)
    Senha.Value = Me.txtSenha.Text.Trim
    cmd.Parameters.Add(Senha)
 
    Try
        conn.Open()
        strRetorno = Convert.ToString(cmd.ExecuteScalar())
        conn.Close()
    Catch ex As Exception
        Response.Write(“Ocorreu uma falha.”)
    Finally
        If Not strRetorno = String.Empty Then
            FormsAuthentication.RedirectFromLoginPage(Me.txtLogin.Text.Trim, _
                Me.chkLembrar.Checked)
        Else
            Me.lblMensagem.Visible = True
        End If
    End Try
 
End Sub
 
Código 2 – Validando o Usuário.

Como podem ver, em primeiro lugar importamos os Namespaces necessários, no caso: System.Data.SqlClient e System.Web.Security. Depois, abrimos conexão com a Base de Dados e através de uma query, passamos como parâmetros o Login e Senha, verificamos se existe algum registro que atenda à essa condição. Caso exista, o usuário é redirecionado para a página “Default.aspx” dentro da pasta “Administracao”, caso contrário uma mensagem será exibida para ele, informando que o acesso foi negado. Lembrando que o CheckBox é passado como o segundo parâmetro para a Sub RedirectFromLoginPage (Linha 31), informando se é ou não para manter o Cookie persistente.

Importante: Não há necessidade de nos preocuparmos em tratarmos os apóstrofos “‘” e ponto-e-vírgula “;” para aqueles que tentarem a “SQL Injection”, pois quando trabalhamos com Parameters, eles ficam encarregados de tratarem isso automaticamente.

Depois de validado, somos direcionados para a página requisitada anteriormente. Veja abaixo:

Figura 4 – Página restrita sendo exibida.

Como passamos para a Sub RedirectFromLoginPage o Login do Usuário (Linha 30 do Código 2), é possível recuperarmos isso durante a sua sessão. Para isso pode fazer:

1
2
3
4
5
6
7
8
 
Imports System.Web.Security
 
Private Sub Page_Load(ByVal sender As System.Object, _
    ByVal e As System.EventArgs) Handles MyBase.Load
 
    Me.lblMensagem.Text = “Bem Vindo à Área Restrita ” & _
        HttpContext.Current.User.Identity.Name
End Sub
 
Código 3 – Podemos ver na Linha 5, como recuperar o Login do Usuário.

O que nos restou agora é fazermos o “Logout” do Usuário. Para isso, utilizaremos o LinkButton “Logout” e assim, ao clicar, a sessão do usuário será finalizada. Veja o exemplo abaixo:

9
10
11
12
13
14
 
Private Sub lnkLogout_Click(ByVal sender As System.Object, _
    ByVal e As System.EventArgs) Handles lnkLogout.Click
 
    FormsAuthentication.SignOut()
    Response.Redirect(“Default.aspx”, True)
End Sub
 
Código 4 – Efetuando o Logout do Usuário.

Utilizamos a Sub SignOut da classe FormsAuthentication para finalizar a sessão do Usuário, e assim ele será novamente redirecionado para a página de Login (“Login.aspx”).

Conclusão: Com o ASP.NET a segurança em nossas aplicações Web ficaram bem mais fáceis de serem implementadas e bem mais seguras. Este artigo explica a parte superficial. Há muitas “features” que possam ser utilizadas para garantirmos o máximo de segurança possível, mas é claro que tudo dependerá de cada Aplicação.

Trabalhando com Arquivos

Frequentemente necessitamos trabalhar com arquivos, sejam eles “*.txt”, “*.xml”, “.csv”, etc. Nesse artigo mostrarei como fazemos para criar, excluir, ler arquivos e diretórios a partir de uma Aplicação Web (ASP.NET).

Separarei por tópicos, onde cada um abordará sobre um assunto. Começaremos pelo Diretórios:

Criando um Diretório


1
2
 
Dim dir As System.IO.Directory
dir.CreateDirectory(“C:Artigos Linha de Codigo”)
 
Código 1 – Criando um Diretório.

Basta criarmos uma variável do tipo System.IO.Directory e executar a função CreateDirectory passando o caminho e nome do diretório a ser criado.

Excluindo um Diretório


1
2
3
4
 
Dim dir As System.IO.Directory
If dir.Exists(“C:Artigos Linha de Codigo”) Then
    dir.Delete(“C:Artigos Linha de Codigo”)
End If
 
Código 2 – Excluindo um Diretório.

É sempre boa prática antes de chamarmos a Sub Delete verificarmos se o diretório existe ou não. Para isso utilize a Function Exists do objeto Directory, que retornará um valor boleano indicando se existe ou não o diretório especificado.

Listando Arquivos e SubDiretórios


1
2
3
4
5
6
7
8
9
10
11
 
Dim dir As New System.IO.DirectoryInfo(“C:Artigos Linha de Codigo”)
Dim subdir As System.IO.DirectoryInfo
Dim arq As System.IO.FileInfo
 
For Each subdir In dir.GetDirectories
    Response.Write(subdir.Name & “<br>”)
Next
 
For Each arq In dir.GetFiles(“*.*”)
    Response.Write(arq.Name & “<br>”)
Next
 
Código 3 – Listando Arquivos e SubDiretórios.

No Código 3 chamo a atenção para a Linha 9. Como o método GetFiles é sobrecarregado, podemos especificar qual o tipo de arquivos queremos listar. No exemplo acima, optei por mostrar todos os arquivos. Se quisessemos exibir apenas arquivos “*.txt”, poderíamos fazer: GetFiles(“*.txt*”).

Vamos agora as operações que podemos realizar com os arquivos.

Criando um Arquivo


1
2
 
Dim arq As New System.IO.FileInfo(“C:Artigos Linha de CodigoNovoArquivo.txt”)
arq.Create()
 
Código 4 – Criando um arquivo.

Escrevendo em um Arquivo


1
2
3
4
5
6
 
Dim strTexto As String = “Israel Aéce.” & System.Environment.NewLine
strTexto =& “Email: israel@projetando.net”
 
Dim stream As New System.IO.StreamWriter(“C:Artigos Linha de CodigoNovoArquivo.txt”)
stream.WriteLine(strTexto)
stream.Close()
 
Código 5 – Escrevendo em um arquivo.

Na instância do StreamWriter já informamos o caminho e o nome do arquivo que deverá ser escrito. Depois chamamos o método WriteLine e passamos a variável “strTexto” para que que ela seja escrita no arquivo.

Excluindo um Arquivo


1
2
3
4
 
Dim arq As New System.IO.FileInfo(“C:Artigos Linha de CodigoNovoArquivo.txt”)
If arq.Exists Then
    arq.Delete()
End If
 
Código 6 – Excluindo um arquivo.

Aqui fazemos da mesma forma qual fizemos para os Diretórios, ou seja, antes de excluirmos verificamos se o arquivo existe. Caso positivo, chamamos o método Delete().

Lendo Arquivos


1
2
3
 
Dim reader As New StreamReader(“C:Artigos Linha de CodigoNovoArquivo.txt”)
Response.Write(reader.ReadToEnd)
reader.Close()
 
Código 7 – Lendo Arquivos.

Utilizando o método ReadToEnd da classe StreamReader não precisamos fazer um loop para percorrer todo o arquivo.

Bem, é importante lembrar que nesse artigo quero apenas dar exemplos de “como fazer para…”. É extremamente importante utilizarmos os tratamentos de erros (Try…Catch…Finally) para executar as rotinas acima, pois não sabemos se os arquivos e/ou diretórios existem ou não, se temos permissão para executar, etc.

CONCLUSÃO: A Plataforma .NET nos trouxe uma grande facilidade na manipulação de arquivos. Sejam eles “*.txt”, “*.xml”, etc. Além de prático as classes como StreamReader e StreamWriter fornece aos desenvolvedores grandes recursos em poucas linhas de código. E para quem está “encantado” na facilidade, espere até conhecer as “My” do Visual Studio .NET Whidbey (http://download.microsoft.com/download/c/7/f/c7f7a575-79ac-4399-9535-3ed57bc292f2/mynamespace.doc).

Behavioral Pattern – Template Method

Em 1995 um grupo de quatro profissionais escreveram um livro chamado “Design Patterns: Elements of Reusable Object-Oriented Software”, cujo os autores ficaram conhecidos como: “A Gangue dos Quatro” (“Gang of Four” ou GoF), sendo eles: Erich Gamma, Ralph Johnson, John Vlissides e Richard Helm.

As Design Patterns contém 23 padrões que estão divididos em três seções:

  • Creational (Criacional)
  • Structural (Estrutural)
  • Behavioral (Comportamental)

Neste artigo abordaremos sobre a Pattern Template Method que está contida dentro da seção Behavioral (Comportamental).

Segundo o GoF, Template Method define um esqueleto de algum algoritmo em um método, adiando a implementação dos passos deste algoritmo para as sub-classes. Esses métodos que são criados nesta classe são chamados de Primitive Operations (Operações Primitivas), e o método em que este algoritmo é implementado o chamamos de Template Method.

Nesta Pattern temos no mínimo dois participantes envolvidos que veremos abaixo:

  • Classe Abstrata: Define as operações primitivas (como métodos abstratos), e o Template Method que definirá o esqueleto do algoritmo.
  • Classe Concreta: Qual implementa as operações primitivas.

O diagrama abaixo ilustrará estes participantes:

Figura 1 – Participantes do Template Method.

Como podemos ver no diagrama acima, a AbstractClass define os métodos abstratos (Primitive Operations) que devem ser implementados nas sub-classes. Além disso, a AbstractClass ainda define um Método Template, que por sua vez irá estruturar as chamadas aos métodos (Primitive Operations), criando assim o esqueleto do algoritmo.

Vamos transformar este Pattern em um exemplo do mundo real. O cenário será: uma classe Autenticacao qual define os seguintes métodos primitivos: VerificaSintaxe e VerificarExistencia e um Template Method chamado Login. A classe não poderá ser instanciada, somente herdá-la. Ficará a cargo das classes que herdarem esta classe, implementarem estes métodos primitivos:

1
2
3
4
5
6
7
8
9
10
11
12
13
 
Public MustInherit Class Autenticacao
 
    Protected MustOverride Function VerificaSintaxe(ByVal password As String) As Boolean
    Protected MustOverride Function VerificarExistencia(ByVal password As String) As Boolean
 
    Public Function Login(ByVal password As String) As Boolean
        If VerificaSintaxe(password) Then
            Return VerificarExistencia(password)
        End If
        Return False
    End Function
 
End Class
 
Código 1 – Classe Base que implementa o Template Method.

Como podemos ver a classe Autenticacao (AbstractClass) criamos os métodos abstratos e o Template Method. Notem que no Template Method (Login) definimos o esqueleto do algoritmo, fazendo chamadas as nossas operações primitivas.

A keyword MustInherit impossibilita da classe Autenticacao ser instanciada, podendo somente ser herdada. Já a keyword MustOverride obriga implementar o método nas sub-classes. Chamo a atenção aqui que por padrão em VB.NET, os métodos são NotOverridable, ou seja, não podem ser sobreescritos nas sub-classes, garantindo assim que o método Login não será alterado (sobreescrito).

Agora nos resta implementar esta classe:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 
Public Class Cliente
 
    Inherits Autenticacao
 
    Protected Overrides Function VerificarExistencia(ByVal password As String) As Boolean
        Select Case password
            Case “Daniel”, “Luciano”, “Rodrigo”, “Israel”
                Return True
            Case Else
                Return False
        End Case
    End Function
 
    Protected Overrides Function VerificaSintaxe(ByVal password As String) As Boolean
        Return (password.Length > 5)
    End Function
 
End Class
 
Código 2 – Classe Filha que herda da Classe “Autenticacao”.

Como dito anteriormente, na classe Cliente herdamos a classe Autenticacao e implementamos os métodos primitivos VerificarExistencia e VerificaSintaxe de acordo com a nossa necessidade ou com as regras de negócio. Podemos aqui reparar a flexibilidade, pois poderíamos implementar de forma diferente para a uma outra classe, por exemplo, Usuarios.

E finalmente, verificando a existência de um Cliente na aplicação:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
 
Sub Main()
    Dim x As New Cliente
    
    Console.WriteLine(x.Login(“Joao”))
    ‘Output: False – Sintaxe incorreta
    
    Console.WriteLine(x.Login(“Israel”))
    ‘Output: True – Usuário encontrado
    
    Console.WriteLine(x.Login(“Juliano”))
    ‘Output: False – Usuário inválido
    
    Console.ReadLine()
End Sub
 
Código 3 – Consumindo a classe “Cliente”.

Ainda poderá existir ocasiões onde será necessário a criação de mais um passo dentro do seu algoritmo. Com isso basta inserir uma Operação Gancho (Hook Operation) no método Template:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 
    ‘…
    
    Public Function Login(ByVal password As String) As Boolean
        If VerificaSintaxe(password) Then
            LogAcesso(password)
            Return VerificarExistencia(password)
        End If
        Return False
    End Function
    
    Protected Overridable Sub LogAcesso(ByVal password As String)
        Console.WriteLine(“Usuario: ” & password)
    End Sub
    
    ‘…
 
Código 4 – Adicionando um metodo “Hook”.

Quando adicionamos um método “Hook”, devemos possibilitar que ele seja sobreescrito, daí o “Gancho”, pois com isso podemos reescrever o método para uma classe específica, tendo assim maior flexibilidade. A keyword Overridable permite que o método seja sobreescrito nas sub-classes (para sobreescrever, devemos utilizar a keyword Overrides)(VB.NET).

CONCLUSÃO: Com este artigo vimos a simplicidade e flexibilidade de como construirmos aplicações Orientadas à Objetos, ganhando facilidade na manutenção devido ao encapsulamento e abstração. Há ainda mais 22 outras Patterns, que quando não nos fornece a solução por completa, ao menos nos mostra o caminho dela.

OOTemplateMethod.rar (14.15 kb)