Páginas

quinta-feira, 5 de janeiro de 2012

Compactando Arquivos Estáticos no ASP.NET

Você já se deparou com um cenário no qual utilize vários arquivos CSS e JS e eles possuem tamanhos grandes e que na sua visão possa causar uma lentidão no carregamento das páginas no cliente?

Eu tive este "problema" alguns dias atrás e necessitava urgentemente compactar os arquivos estáticos do jQuery UI para garantir performance no carregamento das páginas.

A minha solução foi bastante simples. Pensei em obter os arquivos estáticos e compactá-los em runtime utilizando o algoritmo do GZip (classe GZipStream) e passar para o browser este conteúdo compactado identificando que este era um conteúdo com o encoding do tipo GZip.

Para implementar esta solução, primeiro criei um arquivo do tipo Generic Handler (ziparArquivo.ashx), e em seguida alterei o método ProcessRequest para que realizasse o que eu estava imaginando, conforme código comentado:
public void ProcessRequest(HttpContext context)
{
    //Verifico a existência dos parâmetros
    if (context.Request["arquivo"] != null && context.Request["tipo"] != null)
    {
        string arquivo = context.Request["arquivo"].ToString();
        string tipo = context.Request["tipo"].ToString();

        context.Response.ContentType = tipo.Equals(string.Empty) ? "text/plain" : tipo;

        //Informo ao browser que o cache desta chamada será de 5 meses,
        //para que não necessite carregar toda hora que for solicitado.
        context.Response.Cache.SetExpires(DateTime.Now.AddMonths(5));
           
        //Obtenho os bytes do conteúdo do arquivo
        byte[] bufferArquivo = File.ReadAllBytes(context.Server.MapPath(arquivo));

        //Verifico se o browser suporta descompactar arquivos em formato GZip
        if (context.Request.Headers["Accept-Encoding"] != null && context.Request.Headers["Accept-Encoding"].ToString().ToLower().Contains("gzip"))
        {
            //Informo ao browser que o conteúdo deste arquivo é do tipo GZip
            context.Response.AppendHeader("Content-Encoding", "gzip");

            //Verifico se o arquivo já está no Cache do ASP.NET
            if (context.Cache[arquivo] == null)
            {
                //Crio um MemoryStream para armazenar o conteúdo compactado.
                using (MemoryStream msArquivo = new MemoryStream())
                {
                    //Utilizo a classe GZipStream para compactar o arquivo solicitado.
                    using (GZipStream streamGzip = new GZipStream(msArquivo, CompressionMode.Compress))
                    {
                        //Escrevo no objeto do GZip o conteúdo resgatado do arquivo solicitado.
                        streamGzip.Write(bufferArquivo, 0, (int)bufferArquivo.Length);
                        streamGzip.Close();
                    }
                    //Resgato o conteúdo do arquivo, mas agora em seu formato compactado.
                    bufferArquivo = msArquivo.ToArray();
                    //Adiciono o conteúdo do arquivo no Cache do ASP.NET para uma chamada posterior.
                    context.Cache.Add(arquivo, bufferArquivo, null, DateTime.Now.AddMonths(5), Cache.NoSlidingExpiration, CacheItemPriority.Normal, null);
                    msArquivo.Close();
                }
            }
            else
            {
                //Se o arquivo já estiver no Cache do ASP.NET, somente recupero o conteúdo.
                bufferArquivo = (byte[])context.Cache[arquivo];
            }
        }

        //Efetuo um Write no ASHX para que o conteúdo do arquivo compactado ou não seja processado.
        context.Response.OutputStream.Write(bufferArquivo, 0, (int)bufferArquivo.Length);
    }
}
Após criar o ASHX, alterei o código html da MasterPage para que efetuasse a chamada a este novo ASHX, passando por parâmetro o nome dos arquivos estáticos.
<head>
    <title>Página</title>
    <link href="ziparArquivo.ashx?arquivo=jquery-ui-1.8.16.custom.css&tipo=text/css" rel="stylesheet" type="text/css" />
    <script src="ziparArquivo.ashx?arquivo=jquery-1.7.1.min.js&tipo=application/x-javascript" type="text/javascript"></script>
    <script src="ziparArquivo.ashx?arquivo=jquery-ui-1.8.16.custom.min.js&tipo=application/x-javascript" type="text/javascript"></script>
</head>

0 comentários:

Postar um comentário