Pré-Compilação

Uma das mudanças mais impactantes do ASP.NET 2.0 em relação as versões anteriores, ASP.NET 1.x, é a forma de compilarmos a aplicação. Já estavamos acostumados durante a compilação da versão 1.x do ASP.NET, através do Visual Studio .NET, a geração de um arquivo do tipo DLL dentro do diretório bin na raiz da aplicação, que correspondia a todo o código fonte da aplicação em questão.

Nas versões 1.x do ASP.NET tínhamos o conceito de Code-Behind que veio para tornar o ASP.NET muito mais elegante que o ASP clássico. Essa funcionalidade consiste em termos dois arquivos para cada página do site, ou seja, uma página ASPX que contém somente códigos HTML e uma página *.cs (C#) ou *.vb (VB.NET) (dependendo da linguagem escolhida para a aplicação), que é o CodeBehind. As páginas de CodeBehind herdam diretamente da classe base System.Web.UI.Page e o arquivo ASPX, em sua diretiva de página, indica qual o arquivo de CodeBehind que correspondia ao seu código e, em tempo de execução, o ASP.NET faz essa herança automaticamente. A imagem abaixo ilustra isso para ficar mais claro:

Figura 1CodeBehind – ASP.NET 1.x.

Como vemos, o arquivo de CodeBehind está “amarrado” com o arquivo de apresentação (ASPX) através de herança e, o sincronismo é fundamental. Sendo assim, os quando criamos controles via Drag & Drop no VS.NET, obrigatoriamente ele insere o código correspondente à criação deste controle no arquivo de CodeBehind, justamente para termos suporte total à este quando formos programar.

Para resolver esse problema a Microsoft introduziu o que chamamos de Partial Classes ou classe parcial. Elas nos dão uma maior flexibilidade, ou seja, agora o arquivo de código (*.vb ou *.cs) expande (isso é um novo termo) a classe de apresentação (ASPX). Isso quer dizer que, em runtime o ASP.NET combina, ou melhor, mescla uma classe com a outra e a torna uma classe única. Se notar, já não teremos a declaração de controles e os Events Hookups no arquivo de código, pois o ASP.NET também gerará isso automaticamente sem a necessidade de ter previamente declarado.

Quando invocamos pela primeira vez uma página ASPX, onde a aplicação na qual ela faz parte acabou de ser colocada em produção, há a necessidade de compilarmos todo o código da aplicação. Essa tarefa, executada apenas uma única vez (desde que se não mude nada) e gera um retardo na primeira chamada da página que, já é conhecido por desenvolvedores ASP.NET. Para reduzir esse retardo, a Microsoft criou formas de pré-compilarmos a aplicação, quais serão discutidas no decorrer deste artigo.

Formas de Pré-Compilação

Agora na versão 2.0 do ASP.NET já temos duas formas de pré-compilar a aplicação: In-place Pre-compilation e Pre-compilation For Deployment. Vamos a partir daqui analisar cada uma destas opções de compilação.

In-place Pre-compilation

Esta é a forma padrão de compilação do ASP.NET 2.0, ou seja, todas as páginas serão compiladas (inclusive as pastas especiais, como a App_Code) no local em que elas se encontram. Essa forma de compilação é utilizada quando trabalhamos com código in-line (esse tipo de código é quando embutimos o código que roda no servidor misturado com o código de apresentação (ASPX, HTML)) ou mesmo com arquivos *.vb e *.cs separadamente.

Como já podemos perceber, esse comportamento nos dá uma enorme flexibilidade, ou seja, assim que mudarmos algo em algum arquivo ASPX ou mesmo em alguma classe/código de servidor, basta salvarmos e rodar novamente a aplicação que as alterações já estarão em funcionamento. O grande ponto negativo desta forma de compilação é que a primeira requisição sempre será mais demorada, justamente pelo fato de que o ASP.NET deverá primeiramente compilar todos os arquivos ASPX, ASCX, além das pastas especiais como a App_Code; este é o comportamento normal, que é idêntico ao que já acontece na versão 1.x do ASP.NET.

Mesmo que o desenvolvedor não utilizou a forma de código in-line, o ASP.NET compila o arquivo que contém a apresentação (ASPX) e o arquivo de código (*.vb ou *.cs) correspondente, que é especificado no atributo CodeFile da diretiva @Page, na primeira vez que a página é solicitada. Vejamos abaixo as vantagens de desvantagens deste modelo:

Vantagens
  • Fácil de usar;
  • Ótimo para o desenvolvedor;
  • Muda o código e já roda a aplicação.
  • Desvantagens
  • Exige o código na máquina/servidor;
  • A segurança fica comprometida;
  • O arquivo de código e o ASPX estão sempre sincronizados;
  • Qualquer um poderá visualizar o código da aplicação.
  • Com a versão do .NET Framework 2.0, temos um novo utilitário chamado aspnet_compiler.exe, localizado dentro do diretório WINDIR%Microsoft.NETFrameworkv2.0.50215 e que se encarrega de pré-compilar as aplicações ASP.NET. No caso da compilação in-place, o resultado é armazenado dentro do diretório dos arquivos temporários do ASP.NET, que geralmente está localizado no seguinte endereço: %WINDIR%Microsoft.NETFrameworkv2.0.50215Temporary ASP.NET Files. Como neste caso a compilação é feita no mesmo local, definimos então o diretório virtual que será o alvo da compilação e para isso utilizamos o utilitário aspnet_compiler.exe, como é mostrado abaixo:

    aspnet_compiler -v /Teste

    O parâmetro -v indica que é um caminho/diretório virtual e /Teste o nome do diretório virtual que está definido no IIS. Claro que o utilitário aspnet_compiler.exe não fornece apenas essa forma de compilação. Veremos abaixo suas outras funcionalidades bem como seus outros parâmetros.

    Para finalizar essa forma de compilação é importante salientar que seu principal benefício é, além de ter o código disponível para alterarmos, termos um retorno mais rápido na primeira vez que uma página é requisitada mas, com uma grande vantagem, ou seja, ao pré-compilar a aplicação e um erro ocorrer, o aspnet_compiler falhará e mostrará o problema. Já os “warnings” também são exibidos pelo compilador mas, neste caso, a compilação não é abortada.

    Pre-compilation For Deployment

    Além da compilação in-place que vimos acima, temos ainda a compilação para distribuição, que consiste em armazenar o resultado da compilação em um diretório separado, e este é enviado para o servidor de produção. Além disso, ganhamos em segurança, pois todo o código da aplicação é completamente compilado, gerando uma espécie de “executável”. Logo, se sua aplicação sofre mudanças constantes, talvez não seria ideal utilizar este modelo de compilação.

    Também conseguimos essa forma de pré-compilação através do utilitário aspnet_compiler.exe, o qual já foi apresentado anteriormente, e que permite compilarmos todas as páginas e códigos da aplicação. Mas isso não é como acontece nas versões anteriores, ou seja, o código não é embutido em apenas um Assembly (arquivo DLL), mas sim em vários.

    Basicamente informamos à esse utilitário de linha de comando o diretório que contém a aplicação e o diretório de destino da mesma aplicação depois de compilada. Vejamos abaixo a sintaxe para utilizar este utilitário:

    aspnet_compiler -p C:WebSite1 -f -v / C:WebSiteFinal

    Analisando o código acima vemos que o utilitário compilará a aplicação que está no diretório “WebSite1” e armazenará o resultado no diretório “WebSiteFinal”. O parâmetro -f indica que a pasta e seu conteúdo deve ser sobrescrito caso exista. Já o parâmetro -p informa ao utilitário que o caminho que está sendo informado é um caminho físico. Já o parâmetro -v é utilizado para referirmos um caminho virtual, ou seja, de algum diretório dentro do IIS. Neste caso, o compilador utilizará este parâmetro para resolver as referências a partir da raiz da aplicação.

    Para o exemplo deste artigo, a aplicação contém duas páginas ASPX e um classe contida dentro da pasta especial App_Code. Depois de realizada a compilação da aplicação, temos dentro do diretório bin da pasta “WebSiteFinal” os seguintes arquivos:

    Figura 2 – Pasta bin depois da aplicação compilada.

    Nesse processo é também criado um arquivo chamado Precompiled.config na raiz da aplicação. Se analisarmos os “internals” do ASP.NET 2.0 com o Reflector, então chegamos a classe BuildManager do namespace System.Web.Compilation e conseguimos chegar a conclusão que o runtime faz a verificação deste arquivo para certificar se a aplicação é ou não pré-compilada. Se existir o arquivo ele ainda faz algumas verificações dentro do método ReadPrecompMarkerFile. Vejamos abaixo o código na íntegra, extraído através do Reflector:

    private bool IsPrecompiledAppInternal
    {
         get
         {
              if (!this._isPrecompiledAppComputed)
              {
                   this._isPrecompiledApp = 
                        BuildManager.ReadPrecompMarkerFile(
                        HttpRuntime.AppDomainAppPathInternal, 
                        out this._isUpdatablePrecompiledApp);
                   this._isPrecompiledAppComputed = true;
              }
              return this._isPrecompiledApp;
         }
    }
    //....
    private static bool ReadPrecompMarkerFile(string appRoot, out bool updatable)
    {
         updatable = false;
         string text1 = Path.Combine(appRoot, "PrecompiledApp.config");
         if (!File.Exists(text1))
         {
               return false;
         }
         XmlDocument document1 = new XmlDocument();
         try
         {
               document1.Load(text1);
         }
         catch
         {
               return false;
         }
         XmlNode node1 = document1.DocumentElement;
         if ((node1 == null) || (node1.Name != "precompiledApp"))
         {
               return false;
         }
         HandlerBase.GetAndRemoveBooleanAttribute(node1, "updatable", ref updatable);
         return true;
    }

    Se agora abrirmos qualquer página ASPX desta aplicação, encontraremos a seguinte mensagem: “This is a marker file generated by the precompilation tool, and should not be deleted!”. Como a mensagem diz, isso é uma espécie de “marca” que indica que o arquivo ASPX encontra-se compilado em algum local. Apesar da mensagem dizer para não apagarmos o arquivos ASPX, podemos excluí-los e a aplicação continua funcionando normalmente desde que a opção “Verify that file exists” não esteja marcada nas opções do seu diretório virtual.

    Porém um problema existe quando excluímos os arquivos ASPX do diretório, ou seja, se você definir uma página padrão para ser chamada quando o usuário digitar apenas o caminho até o diretório virtual (Exemplo: “http://localhost/Teste”) da sua aplicação, você receberá um erro, pois o ASPNET não encontrará a página.

    Se analisarmos a imagem acima veremos que para cada arquivo ASPX é criado um arquivo com extensão *.compiled dentro do diretório bin, e dentro deste arquivo contém código XML que contém referências do arquivo ASPX e da classe/código (*.vb ou *.cs). Abaixo é mostrado o conteúdo de um destes arquivos:

    <preserve 
         resultType="3" 
         virtualPath="/Default.aspx" 
         hash="7421446ce" 
         filehash="d14ee6041e266d10"      
         flags="10000" 
         assembly="App_Web_ukipp-jc" 
         type="ASP.Default_aspx">
        <filedeps>
            <filedep name="/Default.aspx" />
            <filedep name="/Default.aspx.cs" />
        </filedeps>
    </preserve>

    Além destes arquivos que vimos acima, ainda tempos os arquivos DLLs: App_Code.dll e App_Web_XXXXX.dll. O primeiro é responsável por armazenar o código que está contido na pasta App_Code da aplicação. Já o outro arquivo contém os códigos das páginas *.vb e *.cs da aplicação.

    Como já podemos ver, a quantidade de arquivos gerados é enorme, e ainda existe um problema: a dificuldade no deployment. Como o nome dos arquivos mudam a cada compilação, uma simples alteração no arquivo ASPX ou no código (*.vb ou *.cs) obrigará a recompilarmos a aplicação toda e distribuir novamente (podendo utilizar XCOPY) todos os arquivos da aplicação.

    Mas é claro que para isso temos uma solução, ou seja, ao executarmos o utilitário aspnet_compiler.exe podemos passar o parâmetro -fixednames, que o obrigará a criar os arquivos sempre com o mesmo nome. Isso facilita bastante, já que será preciso apenas enviar ao diretório da aplicação este novo arquivo gerado pela nova página ASPX ou a DLL, se por acaso a alteração for efetuada no código. O código abaixo ilustra essa forma de compilação:

    aspnet_compiler -p C:WebSite1 -f -fixednames -v / C:WebSiteFinal1
    aspnet_compiler  

    Agora, se analisarmos o resultado desta compilação, veremos que foi criado um arquivo DLL para cada página da aplicação:

    Figura 3 – Utilizando o parâmetro -fixednames.

    E para certificar que a página sem a pré-compilação não é acessível, colocamos uma nova página ASPX no diretório da aplicação e em seguida fazemos a requisição para a mesma no browser. O erro, como é mostrado abaixo, será exibido ao cliente informando que a página deve e não foi pré-compilada:

    Figura 4 – Erro quando tentarmos acessar um arquivo não pré-compilado.

    Como falamos, o parâmetro -fixednames ajuda bastante nestes casos, ou seja, bastaríamos recompilar em um diretório temporário e copiar os arquivos gerados devido a criação de uma nova página e mandar para o diretório da aplicação que já está em produção.

    A vantagem desse modelo de compilação é que todo o seu código, inclusive os arquivos ASPX (que contém código HTML e Javascript), ASCX, ASHX e Arquivos *.Master ficam compilados, e ninguém conseguirá ver o código que tem lá dentro. Mas poderá haver situações em que você deseja que seus arquivos fiquem intactos, ou seja, que sejam enviados com o seu código fonte. Para isso, podemos passar o parâmetro -u (que indica updateable) e assim, podemos fazer alguma alteração nos arquivos ASPX, já que temos todo o o fonte ali disponível.

    É importante dizer que os arquivos de back-end, tais como Imagens, arquivos de configuração, CSS, são mantidos e enviados para o destino dentro da mesma estrutura.

    CONCLUSÃO: Como podemos ver no decorrer deste artigo, a forma de compilação para o ASP.NET 2.0 mudou consideravelmente. Apesar de bastante diferente em relação à versão 1.x do ASP.NET, com certeza esse modelo nos traz grandes facilidades e recursos.

    TreeView – ASP.NET 2.0

    Uma colega nos NewsGroups de ASP.NET do MSDN Brasil queria saber como se faz para contar os items de um controle TreeView do ASP.NET. Além disso, também queria fazer como se faz para recuperar os items que estão marcados, isso quando a propriedade ShowCheckBox está definida como All.

    Para ambos os casos, o que deve ser utilizado é uma função recursiva, pois podemos ter nós dentro de nós e assim por diante. Resolvi postar aqui a solução que encontrei para esses dois casos, e poderá de alguma forma ajudar mais alguém que também precise.

    [ Quantidade total de nós ]

    private int _count = 0;
    //….
    private void ResgataQuantidade(TreeNodeCollection coll){
         foreach (TreeNode tn in coll){
              _count += 1;
              if(tn.ChildNodes.Count > 0)
                   ResgataQuantidade(tn.ChildNodes);
         } 
    }

    [ Recuperando os nós selecionados ]

    private void ResgataQuantidadeItemMarcados(TreeNodeCollection coll) {
         foreach (TreeNode tn in coll){
              if(tn.Checked) Response.Write(tn.Text);
                   if(tn.ChildNodes.Count > 0)
                        ResgataQuantidadeItemMarcados(tn.ChildNodes);
         }
    }

    E para chamar qualquer umas das duas funções, basta fazer:

    ResgataQuantidade(this.TreeView1.Nodes);
    Response.Write(“Quantidade: ” + this._count.ToString());
    ResgataQuantidadeItemMarcados(this.TreeView1.Nodes);

    Atlas Preview

    Foi anunciado o Community Preview Site for ASP.NET code-named “Atlas” e o mesmo pode ser acessado neste endereço: http://beta.asp.net/default.aspx?tabindex=7&tabid=47, e tendo mais detalhes abaixo:

    [ Introductory Topics ]
    Understanding AJAX Applications and ASP.NET Atlas
    ASP.NET Atlas Overview

    [ Downloads ]
    Atlas Blank Project VSI — An installer file that adds a template to Visual Studio for creating a new Atlas application.
    Atlas Hands-On-Lab VSI — An installer file that add a template to Visual Studio for creating a project for the 2005 PDC Hands-On Lab.

    [ Hands-on Lab ]
    Lab 1:  Creating a Basic ASP.NET Atlas Web Application
    Lab 2:  Creating a Web Application using the Declarative ASP.NET Atlas Markup
    Lab 3:  Creating an Auto-completion Text Box with ASP.NET Atlas
    Lab 4:  Using ASP.NET Atlas Auto-completion with a Server Control
    Lab 5:  Creating an Atlas Web Application with Data-binding and Templates

    [ Walkthrough Topics ]
    Walkthrough:  Creating a Declarative Web Application with ASP.NET Atlas

    Fonte: http://atlas.asp.net/docs/

    Múltiplos Arquivos de Configuração

    Essas configurações geralmente são valores que precisamos para a aplicação, como por exemplo: string de conexão com a base de dados, servidor de SMTP, entre outras. Veremos abaixo como definimos no arquivo Web.Config da aplicação para que o ASP.NET leia as configurações de um outro arquivo:

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
        <appSettings file="Settings.config"/>
        <!-- outras configurações aqui... -->
    </configuration>

    Como podemos reparar, no atributo file definimos o arquivo chamado “Settings.config” que será o arquivo responsável por armazenar as configurações que nosso projeto utilizará. A estrutura do mesmo é exibida abaixo:

    <?xml version="1.0" encoding="utf-8" ?>
    <appSettings>
        <add key="TesteKey" value="123456" />
    </appSettings>

    Feito isso, podemos normalmente utilizar a forma tradicional que fazemos para recuperar e utilizar um valor que está definido no arquivo Web.Config, utilizando a classe ConfigurationSettings. Abaixo é mostrado como recuperar e escrever este valor:

    using System.Configuration;
    
    //...
    
    Response.Write(ConfigurationSettings.AppSettings["TesteKey"]);

    Linha do DataGrid – Clicando em qualquer lugar

    Para explicar melhor, analise a figura ao lado. Vemos que temos um botão do tipo Select que marca o registro quando o usuário pressionar. Muitas vezes o usuário quer clicar em qualquer lugar desta linha e executar este processo e não somente em cima daquele controle. Este artigo vai abordar este ponto, ou seja, aprender como gerar esta funcionalidade.

    Para que possamos alcançar esse efeito, temos que utilizar o evento ItemDataBound do DataGrid, onde nele deve ser verificado o tipo da linha através da propriedade ItemType para assegurar que é uma linha de registro. Depois desta verificação, recuperamos o controle LinkButton através da coleção de controles que a propriedade Item disponibiliza. De posse do LinkButton, utilizamos o método GetPostBackEventReference da classe Page, onde informamos o controle e é retornado a referência ao código script que é invocado quando o controle é clicado e, consequentemente causa o PostBack. O código abaixo exemplifica o que vimos:

    private void DataGrid1_ItemDataBound(Object sender, 
         System.Web.UI.WebControls.DataGridItemEventArgs e){
    
         if(e.Item.ItemType == ListItemType.AlternatingItem ||
              e.Item.ItemType == ListItemType.Item){
    
              LinkButton lnk = (LinkButton)e.Item.Cells[0].Controls[0];
              e.Item.Attributes.Add("onClick", Page.GetPostBackEventReference(link, ""));
              e.Item.Attributes.Add("style", "cursor:hand");
         }
    }

    Como vemos, o retorno do método GetPostBackEventReference adicionamos como value do evento Javascript onClick, que será executado no cliente e terá a mesma função do botão Select. Por último, apenas adicionamos um style na linha do DataGrid para que o cursor do mouse fique em forma de “mão” para dar a impressão ao usuário que a linha é clicável.

    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&#8221; 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.