Fala Filhotes…

Hoje vou mostrar um “esqueminha” que apesar de não ser novidade (nenhuma) é bastante interessante do ASP.NET, mas primeiro vamos a uma pequena explicação sobre o funcionamento de paginas web.

Imagino que muitos de vocês devem ter aprendido isso na faculdade mas deixa eu fazer um resumão:

Muitos anos atrás quando a internet estava engatinhando, os servidores web usavam apenas arquivos simples como .html, mas a medida que o tempo passou as necessidades também aumentaram. Os programadores precisavam estender a capacidade dos servidores web de alguma forma. Então a Microsoft criou o ISAPI ( Internet Server API) e graças a isso conseguimos extender varias funcionalidades do IIS ( e outros servidores web que são compatíveis com o ISAPI ). Beleza!!! Mas e ai? Cumé qui esse trem funciona?

Bom filhote, é ate bem simples… Veja bem, o ISAPI consiste basicamente de dois componentes: Extensões e Filtros:

Extensões:

As extensões ISAPI são as aplicações que realmente rodam no IIS, e possuem acesso a todas as funcionalidades do IIS. As extensões podem ser implementadas usando DLLs.

As extensões ISAPI devem ser chamada para serem executadas, por exemplo, para chamar a extensão ISAPI usuariocadastro.dll você deve chamar a seguinte URL enviando também os valores que ela precisa via query string:

http://www.siteteste.com.br/usuariocadastro.dll?nome=Andre&idade=22&sexo=M&url=100loop.com.br/

Filtros:

Um filtro ISAPI é um … bom… filtro, entre o servidor web e o cliente. Ao contrario das extensões ISAPI que o usuário tem que chamar a URL para escuta-las, toda requisição para o servidor passa no filtro ISAPI e o próprio servidor passa a requisição para o filtro responsável. Um filtro ISAPI pode criar um log das requisições ou mesmo tratar / modificar alguma informação.

Requisições do ASP.NET

As requisições do ASP.NET são feitas de forma linear, a requisição é passada por todos os módulos, aonde cada um pode realizar qualquer tipo de ação sobre ela. Depois de passar por todos os módulos ela irá para um (apenas um) HTTP handler. O handler processa a requisição e o resultado será novamente enviado a todos os módulos.
Certo! Agora que entendemos um pouco mais sobre o funcionamento do ISAPI e ASP.NET, vamos ao que interessa!

HTTPHandlers

Então, como vimos um HTTPHandler é um código que executa quando uma requisição para um recurso especifico é feita pelo server. Você consegue interagir com a requisição e até enviar um novo retorno ao browser. Para criar um HTTP Handler, você precisa criar uma classe que implemente a interface IHttpHandler ( para um Handler síncrono) ou  IHttpAsyncHandler ( para um handler assíncrono ) ou ate mesmo qualquer classe que implemente IHttpHandlerFactory. Você deve implementar a propriedade IsReusable e o método ProcessRequest para se usar o IHttpHandler e os métodos BeginProcessRequest e EndProcessRequest para o IHttpAsyncHandler . A propriedade IsReusable mostra quando o objeto IHttpHandlerFactory ( O objeto que chama o Handler correto ) vai pôr o Handler numa pool para o reutilizar depois ( aumentando a performance ) ou se vai criar uma nova instancia sempre que precisar dele de novo. O método ProcessRequest é o método chave, o que faz o processamento da requisição.

Beleza! Parece ser muito, muito complicado, mas na verdade é bem simples. Vamos ao exemplo!

Nesse exemplo criaremos um thumbnail, que por padrão SEMPRE encolherá a imagem, quer dizer, se o usuário acessar a imagem diretamente ( 100loop.com.br/imagem.jpg ) ele também à verá encolhida. Então, como eu vejo ela no tamanho original ou aumento o tamanho do thumbnail? bom, é só mandar o tamanho dela via Query String. Estranho? Mais ou menos, dê uma olhada no código:

Primeiro a nossa classe que herda do handler:

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.SessionState;
using System.Configuration;
using System.Web.UI;
using System.Drawing;
using System.IO;
using System.Drawing.Imaging;


namespace HttpHandlers
{
    public class HandlerLogin : IHttpHandler
    {
        /// 
        /// Propriedade necessaria! 
        /// 
        public bool IsReusable
        {
            get
            {
                return false;
            }
        }

        /// 
        /// Metodo que cria um thumbnail de uma imagem, calculando o tamanho para não perder as proporções
        /// 
        ///  Local da imagem 
        ///  Nova largura da imagem 
        ///  Nova Altura da imagem 
           public Bitmap CreateThumbnail(string path, int parWidth, int parHeight)
        {
            // Nosso Bitmap de retorno
            Bitmap bmpOutput = null;

            try
            {
                // Nova bitmap para pegar o arquivo e suas medidas
                Bitmap bitTemp = new Bitmap(path);

                ImageFormat loFormat = bitTemp.RawFormat;
                
                // Variavel para manter a proporção
                decimal ratio;

                int newWidth = 0;

                int newHeight = 0;

                // Se a Imagem for menor que o Thumbnail então retorna a imagem
                if (bitTemp.Width < parWidth && bitTemp.Height < parHeight)

                    return bitTemp;
                // Pega a proporção dividindo a largura pela altura
                ratio = (decimal)bitTemp.Width / bitTemp.Height;

                newHeight = parHeight;
                newWidth = parWidth;
                
                // Checa qual lado é maior para manter a proporção baseado nesse lado.
                if (parHeight > parWidth)
                {               
                    decimal lnTemp = newHeight * ratio;

                    newWidth = (int)lnTemp;
                }
                else
                {
                    decimal lnTemp = newWidth / ratio;

                    newHeight = (int)lnTemp;
                }                              

                
                // Cria o bitmap com as nossas medidas
                bmpOutput = new Bitmap(newWidth, newHeight);

                // Criamos um objeto do tipo Graphics para podermos "desenhar" a imagem no nosso output
                Graphics newGraphic = Graphics.FromImage(bmpOutput);
                
                // Setamos o InterpolationMode para HighQualityBicubic para não perdemos (ou perdemos menos ) qualidade
                // na imagem na hora de encolhê-la. Claro, o tamanho do arquivo fica um pouco maior.
                newGraphic.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;

                // transformamos areas transparentes dos gifs em branco.
                newGraphic.FillRectangle(Brushes.White, 0, 0, newWidth, newHeight);

                // Desenhamos a nossa imagem ( q esta no temp ) com os novos tamanhos no output
                newGraphic.DrawImage(bitTemp, 0, 0, newWidth, newHeight);
                
                // Fechamos o temp
                bitTemp.Dispose();

            }

            catch
            {

                return null;

            }


            // Retornamos a nossa imagem
            return bmpOutput;

        }

        /// 
        /// Metodo principal que irá executar quando uma imagem for chamada (método necessario!)
        /// 
        /// 
        public void ProcessRequest(HttpContext context)
        {
            try
            {

                int width;
                int height;

                //Verifica se o usuario passou a largura da figura
                if (context.Request.QueryString["width"] != null)
                {
                    width = int.Parse(context.Request.QueryString["width"]);
                }
                else
                {
                    width = 100;
                }
                //Verifica se o usuario passou a altura da figura
                if (context.Request.QueryString["height"] != null)
                {
                    height = int.Parse(context.Request.QueryString["height"]);
                }
                else
                {
                    height = 100;
                }                          

                // Pega o caminho do arquivo fisico
                string path = context.Request.PhysicalPath;
                // Pega a extensão para determinar o tipo da imagem
                string contentType = path.Substring(path.LastIndexOf(".") + 1);

                ImageFormat newFormat;

                // Altera o formato dependendo do tipo do arquivo
                switch (contentType)
                {
                    case "gif":
                        newFormat = ImageFormat.Gif;
                        break;
                    case "jpg":
                        newFormat = ImageFormat.Jpeg;
                        contentType = "jpeg";
                        break;
                    case "png":
                        newFormat = ImageFormat.Png;
                        break;
                    default:
                        newFormat = ImageFormat.Jpeg;
                        break;
                }
             
                // Arquivo Bitmap com o thumbnail ja criado
                Bitmap newThumb = CreateThumbnail(path, width, height);

                // Seta o ContentType ( image/jpeg, image/gif ... )
                context.Response.ContentType = "image/" + contentType;

                // Salva a imagem no Output que retornara ao usuario.
                newThumb.Save(context.Response.OutputStream, newFormat);
                newThumb.Dispose();
                
            }
            catch (Exception ex)
            {
                throw;
            }
          

        }
    }
}

Então blz! criamos a classe! Mas para podermos habilitar esse handler precisamos adicionar uma tag a mais no web.config, dentro de <configuration><system.web> adicione essa tag:

Mas o que é essa configuração? uma breve explicação:

Type: Nome da Classe / DLL separado por virgula se for mais de um.

Verb: A lista de verbos que seu componente utiliza, separados por virgula e entre aspas ex: (“GET,POST,HEAD”)

Path: A URL inteira ou parte dela em que o seu Handler ira ser invocado. Ex: *.aspx ( o seu handler executara em todas paginas .aspx ) ou default.aspx (apenas nessa pagina )

Obs: Isso só funciona a partir do IIS 6.0. Antes disso tinha que adicionar o Handler direto no IIS.

Então é isso ai, agora é só criar uma pagina com uma imagem como eu fiz aqui, lembrando que a proporção é realizada automaticamente:

  

Você pode adicionar o método no onclick chamando a imagem com o tamanho maior.

Isso foi só uma demonstração do uso de httpHandlers, há vários outro jeitos de melhorar esse nosso Thumbnail, depende da criatividade/necessidade de cada um. Uma outra coisa bacana seria fazer marca d’água em suas imagens (só em imagens em alguma pasta especifica por exemplo ).

Bom Filhotes, qualquer duvida me avisem! Ate mais!

Fontes:

http://www.15seconds.com/issue/020417.htm

http://msdn.microsoft.com/pt-br/library/7d6sws33%28VS.85%29.aspx