Independente da tecnologia empregada em sua implementação (Web Forms, MVC, WCF), a implantação (deploy) de aplicações Web construídas sob o .NET Framework pode estar sujeita a alguns problemas que passaram de forma despercebida durante o desenvolvimento. Isto pode ser motivado tanto por falhas involuntárias de programadores, quanto por diferenças de configurações entre o servidor destinado à hospedagem de um projeto e os computadores utilizados por programadores durante a codificação.

Muito embora seja impossível conceber uma aplicação livre de falhas, cuidados podem ser tomados para minimizar imprevistos durante o deploy de sistemas Web. O objetivo deste artigo é descrever algumas ações que podem auxiliar neste sentido.

Timeout em páginas com os controles ScriptManager e UpdatePanel

Ao se implementar páginas numa aplicação ASP.NET, o comum é que as mesmas sejam desenvolvidas de uma forma na qual se procure evitar ao máximo problemas de timeout. Um formulário HTML cujo conteúdo demora a ser processado é normalmente abandonado pelos usuários, deixando com isto uma ação inacabada e que, não raro, pode terminar com a gravação de dados inconsistentes.

Uma prática comum para se impedir que isto aconteça é empregar, dentro de soluções Web Forms, os controles UpdatePanel e ScriptManager. Estes dois componentes são extensões do ASP.NET voltadas à utilização de mecanismos de AJAX (sigla do inglês "Asynchronous JavaScript and XML"), tendo por objetivo impedir as famosas "piscadas" (reprocessamento de todo o conteúdo) de uma página.

Por mais que se empreenda um grande esforço em tornar mais rápida uma aplicação Web, ainda poderão existir casos de funcionalidades que demandam um tempo maior a fim de produzir um determinado resultado. Exemplos disto são relatórios do SQL Server Reporting Services acessíveis a partir de sites Web Forms. Considerando que as páginas em que se encontram esses recursos também possuam componentes do AJAX, é bastante alta a probabilidade de ocorrência de problemas de timeout; se isto se confirmar, um erro em JavaScript será gerado e a ação que estava em progresso abortada.

A Figura 1 ilustra este tipo de problema ao se executar uma aplicação Web Forms a partir do Visual Studio 2012.

Timeout em uma página que faz uso de AJAX

Figura 1: Timeout em uma página que faz uso de AJAX

Uma solução para esta questão envolve a alteração do valor da propriedade AsyncPostBackTimeout, para o componente ScriptManager. Por default, esta propriedade assume um tempo de 90 segundos, sendo que no exemplo da Listagem 1 foram definidos 3 minutos (180 segundos).

Listagem 1: Configurando a propriedade AsyncPostBackTimeout de um controle ScriptManager


...

<asp:ScriptManager runat="server" AsyncPostBackTimeout="180">

    ...

</asp:ScriptManager>

Problemas com arquivos de scripts ao se fazer o deploy em um diretório virtual

A esmagadora maioria das aplicações Web fará uso, em algum momento, de instruções JavaScript/JQuery. O uso de scripts em sites está vinculado a ações executadas do lado cliente (browser), de forma a possibilitar uma maior interatividade com os recursos disponibilizados pela solução em questão.

Considerando tudo isso, será mais do que comum em aplicações ASP.NET Web Forms a declaração de arquivos contendo código JavaScript (extensão .js) dentro de Master Pages e outras páginas convencionais. O simples fato de se referenciar scripts a partir da tag criada para esta finalidade (“script”) é uma tarefa extremamente simples, a qual não requer grandes preocupações na maioria dos projetos.

No entanto, existe a probabilidade de erros no acesso a tais scripts em aplicações que foram publicadas em diretórios virtuais. Quando isto acontecer, uma página processada a partir do servidor Web será incapaz de “resolver” (referenciar/localizar) um ou mais arquivos JavaScript, gerando erros visíveis aos seus usuários.

Na Listagem 2, está um exemplo de declaração de script em uma Master Page, com esta referência podendo vir a ocasionar o tipo de problema relatado nesta seção.

Listagem 2: Exemplo de Master Page que faz uso de um arquivo de scripts


<%@ Master Language="C#"
           AutoEventWireup="true"
           CodeBehind="Site.master.cs"
           Inherits="TesteWebForms.SiteMaster" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head runat="server">

    ...

    <script type="text/javascript" src="Scripts/Teste1.js"></script>

    ...

    <asp:ContentPlaceHolder ID="HeadContent" runat="server">
    </asp:ContentPlaceHolder>
</head>
<body>
    <form runat="server">

        ...

        <asp:ContentPlaceHolder ID="MainContent" runat="server"/>

        ...

    </form>
</body>
</html>

Já a Listagem 3 apresenta outro exemplo similar, considerando desta vez uma página Web Forms vinculada à Master Page citada anteriormente.

Listagem 3: Exemplo de Web Page que faz uso de um arquivo de scripts


<%@ Page Language="C#"
         MasterPageFile="~/Site.master"
         AutoEventWireup="true"
         CodeBehind="Default.aspx.cs"
         Inherits="TesteWebForms._Default" %>

<asp:Content ID="HeaderContent" runat="server"
             ContentPlaceHolderID="HeadContent">

    ...

    <script type="text/javascript" src="Scripts/Teste2.js"></script>

    ...

</asp:Content>
<asp:Content ID="BodyContent" runat="server"

    ...

</asp:Content>

Conforme já foi mencionado, a aplicação Web pode não ser capaz de referenciar corretamente os arquivos de scripts Teste1.js e Teste2.js se publicada em um diretório virtual. Uma solução prática para este problema consiste no uso de uma expressão empregando o método ResolveUrl; na Listagem 4 está o código já ajustado da Master Page, ao passo que a Listagem 5 apresenta as alterações equivalentes para a página Web descrita anteriormente.

Listagem 4: Master Page já ajustada


<%@ Master Language="C#"
           AutoEventWireup="true"
           CodeBehind="Site.master.cs"
           Inherits="TesteWebForms.SiteMaster" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head runat="server">

    ...

    <script type="text/javascript"
            src='<%# ResolveUrl("~/Scripts/Teste1.js") %>'></script>

    ...

    <asp:ContentPlaceHolder ID="HeadContent" runat="server">
    </asp:ContentPlaceHolder>
</head>
<body>
    <form runat="server">

        ...

        <asp:ContentPlaceHolder ID="MainContent" runat="server"/>

        ...

    </form>
</body>
</html>

Listagem 5: Web Page já ajustada


<%@ Page Language="C#"
         MasterPageFile="~/Site.master"
         AutoEventWireup="true"
         CodeBehind="Default.aspx.cs"
         Inherits="TesteWebForms._Default" %>

<asp:Content ID="HeaderContent" runat="server"
             ContentPlaceHolderID="HeadContent">

    ...

    <script type="text/javascript"
            src='<%= ResolveUrl("~/Scripts/Teste2.js") %>'></script>

    ...

</asp:Content>
<asp:Content ID="BodyContent" runat="server"

    ...

</asp:Content>

No caso específico da Master Page, um último ajuste também precisará ser efetuado. Dentro do método Page_Load (Listagem 6), acessar o objeto Page e, em seguida, a propriedade Header; invocar então o método DataBind, a fim de que os endereços de script declarados na Master Page possam ser resolvidos.

Listagem 6: Ajuste no evento Page_Load da Master Page


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace TesteWebForms
{
    public partial class SiteMaster : System.Web.UI.MasterPage
    {
        protected void Page_Load(object sender, EventArgs e)
        {

            ...

            Page.Header.DataBind();

            ...

        }

        ...

   }
}

Múltiplos arquivos Web.config: algumas considerações

Outro problema que pode acontecer durante o deploy de soluções ASP.NET diz respeito a modificações realizadas de forma incorreta no Web.config. Arquivos de configuração podem ser criados em qualquer pasta de uma aplicação Web, sendo necessário compreender então a hierarquia seguida pelos mesmos, ou seja, qual arquivo prevalecerá, de forma a se evitar com isto erros inesperados.

No topo de tal hierarquia está o arquivo Machine.config, localizado num diretório-padrão do .NET Framework. Em um computadoe no qual foi instalada a versão 4.5 do .NET, o arquivo Machine.config pode ser encontrado no diretório:

C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config\

Praticamente toda aplicação Web construída sob a tecnologia ASP.NET contará com um arquivo de nome Web.config em seu diretório-raiz (root). Configurações definidas em tal arquivo complementarão (ou mesmo substituirão) itens declarados no arquivo Machine.config.

Por fim, é possível ainda a criação de um Web.config em qualquer diretório de um projeto ASP.NET. Neste último caso, o arquivo correspondente terá precedência sobre o Web.config presente no root da aplicação e o Machine.config. Um exemplo prático disto pode ser observado em aplicações ASP.NET MVC, conforme indicado na Figura 2:

  • Um primeiro arquivo Web.config está situado no diretório-raiz do projeto;
  • Um segundo arquivo Web.config encontra-se localizado o diretório Views, local este em que estão armazenadas estruturas voltadas à renderização de documentos HTML.
Arquivos Web.config criados por padrão em uma aplicação ASP.NET MVC 4

Figura 2: Arquivos Web.config criados por padrão em uma aplicação ASP.NET MVC 4

Considerando tudo o que foi exposto até agora, a seguir estão relacionados alguns cuidados a serem tomados, tendo como intuito evitar problemas com arquivos de configuração dentro de soluções ASP.NET:

  • Precaver-se quanto à cópia de arquivos Web.config em locais incorretos, já que configurações desatualizadas podem vir a sobrepor itens que foram preenchidos corretamente dentro do diretório-raiz da aplicação;
  • Se realmente existir a necessidade de mais de um arquivo Web.config em uma aplicação (como no caso de soluções MVC), certificar-se de que as diferentes configurações requeridas pelo projeto estão sendo definidas nos locais corretos. A declaração errônea de um item no Web.config da pasta Views pode, por exemplo, ocasionar erros em outros pontos da aplicação, os quais esperavam um valor configurado inicialmente no arquivo do diretório-raiz.

Conclusão

Através dos exemplos demonstrados neste artigo, procurei apresentar algumas soluções para problemas frequentemente encontrados no deploy de aplicações ASP.NET. Muitas das situações relatadas passam às vezes de maneira despercebida durante a fase de implementação, algo que pode ser atribuído principalmente a diferenças de configuração entre ambientes (as definições das máquinas de desenvolvimento não coincidem com aquelas encontradas em produção).

No entanto, seguir as recomendações aqui citadas (ou mesmo outras práticas) não torna um sistema livre de falhas e outros imprevistos. Certamente é possível evitar ou, mesmo, atenuar determinados problemas, porém novas ocorrências exigirão a habilidade dos desenvolvedores em solucioná-los com os recursos disponíveis em cada caso.

Espero que essas dicas possam ser úteis no seu dia-a-dia. Até uma próxima oportunidade!