O upload de arquivos corresponde a um tipo de funcionalidade bastante comum em sites voltados aos mais diversos fins. Alguns exemplos de soluções em que este recurso está presente são web mails, redes sociais com mecanismos para a publicação de fotos, sites voltados ao compartilhamento de arquivos entre usuários e portais de anúncios.

A forma como o upload acontece costuma variar de uma aplicação a outra. Em alguns casos, somente é possível o upload de um único arquivo por vez. Em outras situações dois ou mais campos permitem que sejam selecionados vários arquivos (um em cada campo), com os mesmos sendo enviados em conjunto ao servidor para posterior processamento e armazenamento de tais itens.

Por default, o controle HTML empregado em operações de upload (elemento input, com o atributo type configurado com o valor "file") não suporta a seleção de múltiplos arquivos; o próprio componente FileUpload acaba por herdar tal característica. Isto pode se revelar como um empecilho quando houver a possibilidade de submeter um número variável de arquivos, sobretudo se a intenção for evitar que um provável usuário execute repetidas operações de seleção e envio.

Diante desse contexto, o plugin Uploadify (http://www.uploadify.com/) pode representar uma alternativa viável em cenários nos quais um dos pré-requisitos seja o envio de vários arquivos simultaneamente. Contando atualmente com duas versões, este controle baseia-se na biblioteca de scripts jQuery.

Uma das versões do Uploadify é gratuita, fazendo uso de recursos de Flash no processo de upload de arquivos (sem que isto implique a necessidade de se conhecer esta tecnologia). Já a outra versão requer a compra de uma licença, utilizando HTML5 ao invés de Flash, contando ainda com mecanismos adicionais não previstos na biblioteca sem custos.

Além da questão envolvendo o upload de múltiplos arquivos, o fato do plugin Uploadify depender de jQuery possibilita que o mesmo possa ser integrado a aplicações Web construídas nas mais variadas plataformas Web (sites em ASP.NET, Java, PHP e Ruby são alguns exemplos de soluções que podem se beneficiar disto).

Dentre as opções oferecidas pela versão gratuita do Uploadify, podem ser destacados os seguintes recursos:

  • Barras de progresso indicando a evolução no processo de upload dos arquivos;
  • A capacidade de se configurarem restrições, como a quantidade máxima de arquivos para upload, o tamanho máximo para um arquivo que será carregado ou, mesmo, as extensões válidas.

Este artigo tem por finalidade demonstrar como o plugin Uploadify pode ser utilizado em projetos ASP.NET Web Forms. Visando cumprir este objetivo será criada uma aplicação para upload de imagens, com as diferentes funcionalidades da mesma sendo implementadas nas próximas seções.

Criando a solução de exemplo

A aplicação apresentada neste artigo foi criada no .NET framework 4.0, a partir da utilização do Microsoft Visual Studio 2010 Ultimate Edition (o conteúdo pode ser baixado a partir de um link para download que se encontra nesta página).

O exemplo aqui abordado tem como objetivo demonstrar a construção de um site que conta com um mecanismo de upload de múltiplas imagens, possibilitando ainda a pré-visualização de arquivos nas extensões .jpg, .gif. e .png.

Sobre a funcionalidade que permite a exibição de imagens antes de se encerrar a carga das mesmas, algumas considerações precisam ser feitas:

  • A visualização de imagens a partir de um browser exige o upload dos arquivos correspondentes, haja visto o fato do site considerado não possuir acesso a arquivos que se encontram na máquina do usuário;
  • Diante de tal restrição, uma alternativa seria o upload para um diretório temporário e, se o usuário confirmar esta operação, a transferência dos arquivos envolvidos para uma área de armazenamento definitiva;
  • Eventuais arquivos que permaneçam no diretório temporário mencionado seriam excluídos por algum processo/serviço criado especificamente para esta finalidade, uma vez que representam ações não concluídas (devido a um fechamento abrupto do browser, falhas no acesso à aplicação a partir do computador de um usuário etc.).

Para gerar o projeto de testes será necessário, dentro do Visual Studio, acessar o menu File, opção New, sub opção Project. Dentro da tela New Project (Figura 1) selecionar o template ASP.NET Web Application, informando no campo Name o nome da aplicação a ser gerada (“TesteUploadWebForms”, neste caso); no campo Location é possível ainda definir o diretório no qual serão criados os arquivos para este projeto.

Criando um projeto ASP.NET para testes

Figura 1: Criando um projeto ASP.NET para testes

Após isto, criar dentro da Web Application TesteUploadWebForms duas pastas (pressionando botão direito do mouse sobre o projeto e escolhendo a opção “Add” e, em seguida “New Folder”: PreVisualizacao e Repositorio. A primeira destas pastas se destina ao armazenamento temporário de arquivos, ao passo que a segunda conterá imagens cujo carregamento foi confirmado por um usuário.

Criação das classes para a manipulação de imagens

Após a criação do projeto TesteUploadWebForms, será necessário prosseguir com a geração dos tipos utilizados pelas funcionalidades relacionadas ao upload de imagens e, consequentemente, à exibição destas.

A primeira destas classes será chamada de Arquivo: clicar dentro do Solution Explorer com o botão direito do mouse sobre a Web Application TesteUploadWebForms, escolhendo em seguida no menu de atalho a opção Add, sub opção New Item. Neste momento será exibida a tela Add New Item (Figura 2); preencher o campo Name com “Arquivo.cs”.

Criando o arquivo para implementação da classe Arquivo

Figura 2: Criando o arquivo para implementação da classe Arquivo

Na Listagem 1 está a implementação do tipo Arquivo. Nessa estrutura constarão informações como o nome do arquivo (propriedade NomeArquivo), o caminho (temporário ou definitivo) em que o mesmo se encontra (propriedade CaminhoCompleto), o endereço da imagem correspondente dentro do site (propriedade URL), a data de criação/upload (propriedade DataCriacao) e o tamanho em bytes (propriedade Tamanho).

Listagem 1: Classe Arquivo


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

namespace TesteUploadWebForms
{
    public class Arquivo
    {
        public string NomeArquivo { get; set; }
        public string CaminhoCompleto { get; set; }
        public string URL { get; set; }
        public DateTime DataCriacao { get; set; }
        public long Tamanho { get; set; }
    }
}

A classe Arquivo servirá de base para a realização de operações a partir de dois outros tipos (que serão criados seguindo também os passos já descritos anteriormente): PreVisualizacaoHelper (empregado no processo de pré-visualização de imagens) e RepositorioArquivosHelper (utilizado na manipulação de arquivos que constarão no repositório de armazenamento definitivo).

A Listagem 2 apresenta o código-fonte referente ao tipo estático PreVisualizacaoHelper. Foram declaradas nesta classe os métodos:

  • GetPathArquivoTemporario: retorna o caminho temporário de uma imagem (salva para efeitos de pré-visualização);
  • AdicionarArquivoListaPreVisualizacao: adiciona a uma lista (na sessão do usuário atual) um arquivo que estará sendo visualizado antes da confirmação do processo de upload;
  • RemoverArquivosListaPreVisualizacao: verifica todos os arquivos que constam para pré-visualização na sessão atual, excluindo posteriormente os mesmos e, finalmente, removendo tal coleção das informações de estado de um usuário.

Estão sendo utilizados nos diferentes métodos estáticos recursos disponibilizados pelos seguintes tipos do .NET Framework:

  • HttpServerUtility (namespace System.Web): classe que permite a realização de operações ligadas ao processamento de requisições recebidas por um servidor Web;
  • HttpSessionState (namespace System.Web.SessionState): possibilita a manipulação de informações associadas à sessão de um usuário conectado a um site ASP.NET;
  • FileInfo (System.IO): classe através da qual se consegue efetuar a manipulação de informações sobre arquivos;
  • File (System.IO): disponibiliza funcionalidades que permitem criar, mover ou, mesmo, excluir fisicamente um arquivo.

O método GetPathArquivoTemporario recebe como parâmetros uma instância do tipo HttpServerUtility (“server”) e uma string com o nome original de um arquivo (“nomeOriginal”) a partir do qual será feito o upload. Por meio da referência “server” é acionado o método MapPath, devolvendo como resultado o caminho físico em que está a pasta “PreVisualizacao” (é neste diretório em que se salvam as imagens). A este endereço será concatenado o nome de cada arquivo, o qual se inicia pela data/hora em que aconteceu o upload, seguido pela identificação original da imagem (com isso se evita a sobreposição de imagens com nomenclaturas idênticas).

Já a operação AdicionarArquivoListaPreVisualizacao recebe uma referência que aponta para a sessão de um usuário (tipo HttpSessionState), além do caminho de uma imagem que foi carregada no diretório temporário (“PreVisualizacao”). Uma coleção de objetos da classe Arquivo estará vinculada à sessão de um usuário; instâncias baseadas no tipo Arquivo são geradas a partir de informações de referências do tipo FileInfo, sendo por fim associados ao agrupamento de objetos vinculado à estrutura baseada em HttpSessionState.

Importante destacar o fato dos métodos GetPathArquivoTemporario e AdicionarArquivoListaPreVisualizacao terem sido marcados com o atributo MethodImplAttribute (namespace System.Runtime.CompilerServices), o qual está recebendo em seu construtor o valor de enumeration MethodImplOptions.Synchronized. Tratam-se de operações sincronizadas, ou seja, caso uma primeira requisição esteja executando algum desses métodos, chamadas subsequentes serão forçadas a aguardar o término de tal processamento (uma destas solicitações será então escolhida, com isto se repetindo sucessivamente até a última chamada).

A operação RemoverArquivosListaPreVisualizacao percorre a lista de objetos vinculada à sessão de um usuário, de forma que se excluam fisicamente imagens associadas a instâncias do tipo Arquivo (via método Delete da classe File). Geralmente, esta ação será disparada quando um usuário solicitar abortar a carga definitiva de uma ou mais imagens.

Listagem 2: Classe PreVisualizacaoHelper


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.SessionState;
using System.IO;
using System.Runtime.CompilerServices;

namespace TesteUploadWebForms
{
    public static class PreVisualizacaoHelper
    {
        [MethodImpl(MethodImplOptions.Synchronized)]
        public static string GetPathArquivoTemporario(
            HttpServerUtility server,
            string nomeOriginal)
        {
            return server.MapPath("~/PreVisualizacao/") +
                String.Format("[{0}]{1}",
                    DateTime.Now.ToString("yyyyMMddhhmmssfff"),
                    nomeOriginal);
        }

        [MethodImpl(MethodImplOptions.Synchronized)]
        public static void AdicionarArquivoListaPreVisualizacao(
            HttpSessionState session,
            string caminhoArquivo)
        {
            List<Arquivo> arquivos;
            if (session["ArquivosPreVisualizacao"] != null)
            {
                arquivos = (List<Arquivo>)
                    session["ArquivosPreVisualizacao"];
            }
            else
            {
                arquivos = new List<Arquivo>();
                session["ArquivosPreVisualizacao"] = arquivos;
            }

            FileInfo f = new FileInfo(caminhoArquivo);

            Arquivo arqImagem = new Arquivo();
            arqImagem.NomeArquivo =
                f.Name.Substring(f.Name.IndexOf("]") + 1);
            arqImagem.CaminhoCompleto = f.FullName;
            arqImagem.URL = "~/PreVisualizacao/" + f.Name;
            arqImagem.DataCriacao = f.CreationTime;
            arqImagem.Tamanho = f.Length;
            arquivos.Add(arqImagem);
        }

        public static void RemoverArquivosListaPreVisualizacao(
            HttpSessionState session)
        {
            if (session["ArquivosPreVisualizacao"] != null)
            {
                List<Arquivo> arquivos =
                    (List<Arquivo>)session["ArquivosPreVisualizacao"];
                foreach (Arquivo arqImagem in arquivos)
                {
                    File.Delete(arqImagem.CaminhoCompleto);
                }

                session["ArquivosPreVisualizacao"] = null;
            }
        }
    }
}

A definição da classe estática RepositorioArquivosHelper é apresentada na Listagem 3. Este tipo é formado pelas seguintes operações:

  • GetArquivosRepositorio: responsável por listar todos os arquivos que constam na pasta “Repositorio” (de uploads que foram concluídos com o consentimento de usuários que postaram uma ou mais fotos);
  • ConfirmarUploadArquivos: método executado para transferir arquivos da pasta temporária (“PreVisualizacao”) para o diretório de armazenamento definitivo (Repositorio).

Além dos tipos HttpServerUtility, HttpSessionState e File usados em PreVisualizacaoHelper, RepositorioArquivosHelper depende ainda da classe DirectoryInfo. Esta última é uma estrutura nativa do .NET Framework, normalmente empregada em tarefas que envolvam a obtenção de informações sobre diretórios.

O método GetArquivosRepositorio retorna como resultado uma coleção de instâncias do tipo Arquivo, as quais contêm informações relativas ao diferentes arquivos que se encontram no diretório “Repositorio”. Estes dados são obtidos, por sua vez, através da invocação da operação GetFiles sobre um objeto baseado na classe DirectoryInfo.

Já a operação ConfirmarUploadArquivos percorre a coleção de objetos do tipo Arquivo associados à sessão de um usuário, de maneira a transferir imagens que se encontram no diretório temporário para a pasta em que serão armazenadas definitivamente (via método estático Move da classe File).

Listagem 3: Classe RepositorioArquivosHelper


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.SessionState;
using System.IO;

namespace TesteUploadWebForms
{
    public static class RepositorioArquivosHelper
    {
        public static List<Arquivo> GetArquivosRepositorio(
            HttpServerUtility server)
        {
            List<Arquivo> arquivos = new List<Arquivo>();

            DirectoryInfo diretorio = new DirectoryInfo(
                server.MapPath("~/Repositorio/"));
            arquivos.AddRange(
                from a in diretorio.GetFiles()
                orderby a.CreationTime descending
                select new Arquivo()
                {
                    NomeArquivo = a.Name.Substring(
                        a.Name.IndexOf("]") + 1),
                    CaminhoCompleto = a.FullName,
                    URL = "~/Repositorio/" + a.Name,
                    DataCriacao = a.CreationTime,
                    Tamanho = a.Length
                });
            
            return arquivos;
        }

        public static void ConfirmarUploadArquivos(
            HttpServerUtility server,
            HttpSessionState session)
        {
            if (session["ArquivosPreVisualizacao"] != null)
            {
                List<Arquivo> arquivos =
                    (List<Arquivo>)session["ArquivosPreVisualizacao"];
                foreach (Arquivo arqImagem in arquivos)
                {
                    File.Move(
                        arqImagem.CaminhoCompleto,
                        server.MapPath("~/Repositorio/") +
                        new FileInfo(arqImagem.CaminhoCompleto).Name);
                }

                session["ArquivosPreVisualizacao"] = null;
            }
        }
    }
}

Implementando o mecanismo para upload de imagens

Conforme já mencionado anteriormente, o upload de múltiplas imagens acontecerá por meio do uso de jQuery (com um plugin que combina Javascript e a tecnologia Flash). Diante disso, conclui-se que deverá existir algum dispositivo dentro da aplicação Web (e que não necessariamente será uma página ASP.NET) responsável por receber requisições que contenham imagens, executando operações que irão salvar os arquivos correspondentes no diretório de armazenamento temporário (“PreVisualizacao”).

A implementação de um dispositivo que conte com este comportamento pode ser feita por meio de um recurso conhecido como ASP.NET Generic Handler. Este tipo de estrutura é identificado geralmente pela extensão .ashx, representando uma implementação da interface IHttpHandler (namespace System.Web).

Do ponto de vista arquitetural, classes que derivam da interface IHttpHanlder são empregadas no processamento de requisições HTTP, sem que isto implique obrigatoriamente na produção de resultado sob a forma de HTML. Trata-se, portanto, de um artifício que pode ser bastante útil para executar ações com as mais variadas finalidades sobre solicitações enviadas por um usuário. Constituem bons exemplos disto tarefas como a gravação de registros em log, o upload de arquivos que constem num pacote que a aplicação está recebendo, o redirecionamento para um caminho diferente daquele que consta na requisição original, dentre outras possibilidades.

A criação de um Generic Handler dentro de uma aplicação ASP.NET pode ser feita clicando-se com o botão direito do mouse sobre o projeto (a partir da janela Solution Explorer), acionando em seguida no menu de contexto Add > New Item. Aparecerá então a tela Add New Item (Figura 3); selecionar o template "Generic Handler", preenchendo no campo Name o valor "UploadHandler.ashx".

Criando o Handler UploadHandler.ashx

Figura 3: Criando o Handler UploadHandler.ashx

Na Listagem 4 é apresentada a definição do Handler UploadHandler.ashx.

Conforme pode ser observado, a classe UploadHandler deriva das interfaces IHttpHandler e IRequiresSessionState (namespace System.Web.SessionState).

O uso da interface IRequiresSessionState ocorre em virtude da necessidade de UploadHandler manipular informações vinculadas à sessão de um usuário. Importante frisar que IRequiresSessionState não requer que as classes baseadas na mesma definam métodos ou, mesmo, proprieadades.

No caso específico de IHttpHandler, estão sendo implementados:

  • O método ProcessRequest será responsável pelo processamento de requisições envolvendo o upload de imagens. Esta operação recebe como parâmetro uma instância do tipo HttpContext (namespace System.Web), a qual permite o acesso a dados e recursos relacionados diretamente à requisição (propriedade Request) que se está processando num determinado instante ou ainda, à sessão do usuário atual (propriedade Session). O conteúdo de um arquivo que esteja sendo enviado para upload pode ser obtido por meio do item Files da propriedade Request (que retornará uma instância do tipo HttpPostedFile; o método SaveAs deste último possibilita a gravação da imagem fisicamente). Além disso, é possível notar o uso da classe PreVisualizacaoHelper, sendo que essa estrutura é acionada com vistas ao armazenamento temporário de arquivos de imagens;
  • A propriedade boolean IsReusable, que indica se uma outra requisição (além da atual) poderá reutilizar uma instância do Handler em questão. Costumeiramente, retorna-se false, de maneira a forçar a geração de uma nova referência do Handler considerado para cada nova solicitação recebida.

Listagem 4: Handler UploadHandler.ashx


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Configuration;
using System.Web.SessionState;

namespace TesteUploadWebForms
{
    public class UploadHandler : IHttpHandler, IRequiresSessionState
    {
        public void ProcessRequest(HttpContext context)
        {
            HttpPostedFile arquivo =
                context.Request.Files["Filedata"];
            string caminhoArquivo = PreVisualizacaoHelper
                .GetPathArquivoTemporario(context.Server, 
                    arquivo.FileName);
            arquivo.SaveAs(caminhoArquivo);
            PreVisualizacaoHelper
                .AdicionarArquivoListaPreVisualizacao(
                     context.Session, caminhoArquivo);
        }

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
}

Implementação do site para testes

Durante a criação da Web Application TesteUploadWebForms foi utilizado o template padrão que é disponibilizado pelo Visual Studio. Devido a este motivo, algumas alterações nas páginas que foram criadas automaticamente serão efetuadas, com o intuito de simplificar a aparência e a estrutura da aplicação de exemplo.

Na Listagem 5 está o código que define a aparência da Master Page Site.Master, a qual é referenciada pelas demais páginas do site. Esse tipo de estrutura conta normalmente com elementos visuais (menus, abas, legendas etc.) comuns às várias páginas de uma aplicação. Assim, a utilização deste recurso evita a repetição de controles e outros itens ao longo de uma solução Web.

Listagem 5: Código da Master Page Site.Master


<%@ Master Language="C#" AutoEventWireup="true"
    CodeBehind="Site.master.cs"
    Inherits="TesteUploadWebForms.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">
    <title></title>
    <link href="~/Styles/Site.css" rel="stylesheet" type="text/css" />
    <asp:ContentPlaceHolder ID="HeadContent" runat="server">
    </asp:ContentPlaceHolder>
</head>
<body>
    <form runat="server">
    <div class="page">
        <div class="header">
            <div class="title">
                <h1>
                    Upload de múltiplos arquivos em ASP.NET Web Forms
                </h1>
            </div>
            <div class="clear hideSkiplink">
                <asp:Menu ID="NavigationMenu" runat="server"
                     CssClass="menu" EnableViewState="false"
                     IncludeStyleBlock="false"
                     Orientation="Horizontal">
                    <Items>
                        <asp:MenuItem NavigateUrl="~/Default.aspx"
                             Text="Home"/>
                        <asp:MenuItem NavigateUrl="~/Upload.aspx"
                             Text="Upload"/>
                        <asp:MenuItem NavigateUrl="~/About.aspx"
                             Text="Sobre"/>
                    </Items>
                </asp:Menu>
            </div>
        </div>
        <div class="main">
            <asp:ContentPlaceHolder ID="MainContent" runat="server"/>
        </div>
        <div class="clear">
        </div>
    </div>
    <div class="footer">
        
    </div>
    </form>
</body>
</html>

Será necessário agora prosseguir com a implementação da funcionalidade para visualização de imagens cujo processo de upload já foi concluído (armazenadas no diretório “Repositorio”). Isto acontecerá dentro da página Default.aspx, a qual foi gerada de maneira automática ao se criar o projeto TesteUploadWebForms.

Adicionar ao formulário Default.aspx uma GridView de nome “grdArquivos”. Este controle permitirá a visualização de imagens que já foram carregadas a partir do site.

OBSERVAÇÃO IMPORTANTE: Por questões de simplificação, o código da maioria dos arquivos de extensão .aspx está sendo omitido, sendo possível se obter os mesmos a partir do link para download do material deste artigo.

Na Listagem 6 é apresentado o código-fonte referente à página Default.aspx. O evento Page_Load foi implementado de maneira a exibir todos os arquivos que constem na pasta “Diretorio”; para isto, é realizada uma chamada ao método GetArquivosRepositorio da classe estática RepositorioArquivosHelper.

Listagem 6: Implementação da página Default.aspx


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

namespace TesteUploadWebForms
{
    public partial class _Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
            {
                grdArquivos.DataSource =
                    RepositorioArquivosHelper
                       .GetArquivosRepositorio(Server);
                grdArquivos.DataBind();
            }
        }
    }
}

Antes de prosseguir com a implementação da funcionalidade de upload, será necessário efetuar o download do plugin Uploadify, assim como da biblioteca de scripts jQuery (a aplicação aqui descrita faz uso da versão 1.8.1 do jQuery).

No caso específico do plugin Uploadify, um arquivo compactado conterá os diversos recursos que precisarão ser adicionados ao projeto TesteUploadWebForms.

Copiar para a pasta Scripts da aplicação os seguintes arquivos (remover scripts que foram criados automaticamente, os quais representam uma versão mais antiga de jQuery):

  • jquery-1.8.1.min.js (a biblioteca jQuery propriamente dita);
  • jquery.uploadify.js (scritps do plugin Uploadify);
  • uploadify.swf (componente Flash empregado no upload de múltiplos arquivos).

Já no diretório Styles, incluir o arquivo uploadify.css; esta folha de estilos contém toda a formatação requerida para exibição do componente para upload de vários arquivos simultaneamente.

Por fim, criar uma pasta de nome “img”, adicionando o arquivo uploadify-cancel.png à mesma.

Para a implementação do mecanismo de upload de imagens será criado o formulário Upload.aspx: clicar com o botão direito do mouse sobre a Web Application TesteUploadWebForms, selecionando no menu de atalho a opção Add, subopção New Item. Neste momento será exibida a tela Add New Item (Figura 4); marcar o template “Web Form using Master Page” e preencher o campo Name com o valor “Upload.aspx”.

Acionando a opção “Add” será necessário definir a Master Page à qual estará vinculado o Web Form em questão (Figura 5). A única opção possível no caso é “Site.Master”; finalizar então este processo clicando no botão “OK”.

Criando os arquivos para implementação da página Upload.aspx

Figura 4: Criando os arquivos para implementação da página Upload.aspx

Selecionando a Master Page da página Upload.aspx

Figura 5: Selecionando a Master Page da página Upload.aspx

Na Listagem 7 encontra-se a implementação da página Upload.aspx. Este formulário acessa o método RemoverArquivosListaPreVisualizacao da classe PreVisualizacaoHelper: na prática, toda vez que um usuário acessar a página Upload.aspx prováveis arquivos existentes na pasta "PreVisualizacao" e vinculados à sessão do mesmo serão excluídos fisicamente (pelo fato do usuário em questão não ter concluído o processo de carga das imagens; por ter fechado o browser abruptamente, por exemplo).

Listagem 7: Implementação da página Upload.aspx


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

namespace TesteUploadWebForms
{
    public partial class Upload : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
            {
                PreVisualizacaoHelper
                    .RemoverArquivosListaPreVisualizacao(Session);
            }
        }
    }
}

Já na Listagem 8 está o código correspondente ao conteúdo exibido por meio da página Upload.aspx. Um controle do tipo FileUpload chamado “uploadImagens” foi adicionado a este formulário. Além disso, estão sendo referenciados os arquivos uploadify.css, jquery-1.8.1.min.js e jquery.uploadify.js.

Dentro da seção de script é possível observar que o método uploadify é invocado a partir do controle uploadImagens. Esta ação faz com que o componente para upload seja vinculado ao plugin Uploadify, de maneira que ao se clicar no mesmo seja exibida uma tela para a seleção de múltiplos arquivos.

O parâmetro recebido pelo método uploadify representa um exemplo de utilização de objeto no formato JSON (sigla do inglês "Javascript Object Notation"). Este padrão possibilita a serialização de objetos como texto, sendo uma alternativa ao uso de XML na transferência de informações a partir de uma rede. O formato JSON é empregado costumeiramente em aplicações Web que utilizam recursos em AJAX e de Javascript/JQuery.

Objetos no formato JSON são compostos por pares de informações, com cada um destes contando um identificador (string que identifica o nome de propriedade) e seu respectivo valor. Podem ser empregados para a representação de valores em JSON os seguintes tipos de dados: Numeric, String, Boolean, Array (os diversos elementos devem estar separados por vírgula e constando dentro de colchetes) e null.

As seguintes configurações estão sendo preenchidas ao se realizar uma chamada ao método uploadify:

  • swf: caminho do componente Flash utilizado no upload de múltiplos arquivos;
  • uploader: endereço da estrutura responsável pelo processamento de arquivos enviados via HTTP (neste caso específico, o Handler que já foi implementado anteriormente);
  • auto: indica se o upload de um ou mais arquivos selecionados será feito automaticamente ou não (tão logo se feche a tela de seleção). No exemplo que está sendo implementado esse comportamento foi ativado, de maneira que a transferência das imagens para a pasta temporária (“PreVisualizacao”) possibilite a pré-visualização antes do armazenamento definitivo das mesmas;
  • multi: atributo que indica se acontecerá ou não o upload de múltiplos arquivos;
  • width: largura em pixels do controle em tela;
  • fileTypeDesc: descritivo dos tipos de arquivos possíveis de selecionar;
  • fileTypeExts: funciona como um filtro, determinando quais extensões de arquivos serão permitidas para upload;
  • progressData: define como será demonstrado o progresso de um upload por meio de uma barra (“percentage” indica a evolução percentual; “speed” exibe tal progresso sem uma referência numérica);
  • buttonText: texto que aparecerá no botão que ao ser clicado exibirá uma tela para seleção de arquivos;
  • uploadLimit: número máximo de arquivos por operação de upload;
  • fileSizeLimit: tamanho máximo de um arquivo enviado para upload;
  • onQueueComplete: função que será executada quando se concluir o processo de upload de um ou mais arquivos.

Caso uma ou mais imagens tenham sido selecionadas e, com o processo de carga temporária ocorrendo com sucesso, a função associada à propriedade onQueueComplete será acionada. Como resultado disto o usuário será redirecionado para uma tela de nome ConfirmacaoUpload.aspx.

Listagem 8: Página Upload.aspx


<%@ Page Title="" Language="C#" MasterPageFile="~/Site.Master"
    AutoEventWireup="true" CodeBehind="Upload.aspx.cs"
    Inherits="TesteUploadWebForms.Upload" %>

<asp:Content ID="Content1" ContentPlaceHolderID="HeadContent"
     runat="server">
    <link href="Styles/uploadify.css" rel="stylesheet"
         type="text/css" />
    <script type="text/javascript"
         src="Scripts/jquery-1.8.1.min.js"></script>
    <script type="text/javascript"
         src="Scripts/jquery.uploadify.js"></script>
    <script type="text/javascript">

        $(document).ready(function () {
            $("#<%=uploadImagens.ClientID %>").uploadify(
            {
                'swf': 'Scripts/uploadify.swf',
                'uploader': 'UploadHandler.ashx',
                'auto': true,
                'multi': true,
                'width': 370,
                'fileTypeDesc': 'Arquivos de imagem',
                'fileTypeExts': '*.gif; *.jpg; *.png',
                'progressData': 'percentage',
                'buttonText': 
                     'Clique aqui para selecionar o(s) arquivos(s)',
                'uploadLimit': 5,
                'fileSizeLimit': '4MB',
                'onQueueComplete': function (queueData) {
                    if (queueData.uploadsSuccessful > 0) {
                        alert('Número de imagens lidas = ' +
                            queueData.uploadsSuccessful + '.\n\n' +
           'Será exibida agora a pré-visualização do(s) arquivo(s).');
                        
                        window.location.replace(
                            'ConfirmacaoUpload.aspx');
                    }
                }
            });
        });

    </script>
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent"
     runat="server">
    <div style="text-align: center; padding-left: 250px; padding-top: 50px;">
        <asp:FileUpload ID="uploadImagens" runat="server" />
    </div>
</asp:Content>

Para finalizar a construção deste projeto de exemplo, será implementada agora a página ConfirmacaoUpload.aspx (para criar os arquivos necessários seguir os mesmos passos já descritos anteriormente na geração do Web Form Upload.aspx). Adicionar a este novo formulário os controles que se encontram listados na Tabela 1.

Tipo do ControleNome do Controle
GridViewgrdPreVisualizacao
ButtonbtnConfirmarUpload
ButtonbtnCancelarUpload

Tabela 1: Controles a serem adicionados à página ConfirmacaoUpload.aspx

O código que implementa a funcionalidade de confirmação de upload está na Listagem 9. A partir desta tela será possível visualizar as imagens que o usuário selecionou (evento Page_Load carregando na grid os arquivos que se encontram na pasta “PreVisualizacao”), bem como confirmar tal processo (evento btnConfirmarUpload_Click) ou ainda, abortar esta ação (evento btnCancelarUpload_Click).

No caso do evento Page_Load, o método correspondente utiliza a sessão atual, associando ao controle de nome grdPreVisualizacao informações sobre arquivos e permitindo ainda a pré-visualização de cada um destes.

Quanto ao método btnConfirmarUpload_Click, na definição do mesmo é possível notar uma chamada à operação ConfirmarUploadArquivos que foi definida no tipo estático RepositorioArquivosHelper.

Já no código do evento btnCancelarUpload_Click é efetuada uma chamada ao método estático RemoverArquivosListaPreVisualizacao de PreVisualizacaoHelper, com vistas a excluir da sessão (e também fisicamente) quaisquer imagens que tenham sido carregadas para pré-visualização.

Listagem 9: Implementação da página ConfirmacaoUpload.aspx


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

namespace TesteUploadWebForms
{
    public partial class ConfirmacaoUpload : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
            {
                bool operacaoInvalida = false;
                List<Arquivo> arquivos = null;

                if (Session["ArquivosPreVisualizacao"] == null)
                    operacaoInvalida = true;
                else
                {
                    arquivos = (List<Arquivo>)Session[
                        "ArquivosPreVisualizacao"];
                    operacaoInvalida = arquivos.Count == 0;
                }

                if (operacaoInvalida)
                    throw new Exception("Operação inválida!");

                grdPreVisualizacao.DataSource = arquivos;
                grdPreVisualizacao.DataBind();
            }
        }

        protected void btnConfirmarUpload_Click(
            object sender, EventArgs e)
        {
            RepositorioArquivosHelper.ConfirmarUploadArquivos(
                Server, Session);
            Response.Redirect("~/Default.aspx");
        }

        protected void btnCancelarUpload_Click(
            object sender, EventArgs e)
        {
            PreVisualizacaoHelper
                .RemoverArquivosListaPreVisualizacao(Session);
            Response.Redirect("~/Upload.aspx");
        }
    }
}

Ao término dos ajustes aqui descritos, o projeto TesteUploadWebForms possuirá uma estrutura como a que consta na Figura 6.

Projeto TesteUploadWebForms ao término de todos os ajustes

Figura 6: Projeto TesteUploadWebForms ao término de todos os ajustes

Executando a aplicação de testes

Iniciando a execução da solução implementada neste artigo, será apresentada uma tela como aquela que consta na Figura 7. Neste momento inicial, nenhum upload de imagens foi realizado ainda.

Aplicação TesteUploadWebForms em execução

Figura 7: Aplicação TesteUploadWebForms em execução

Acessando o link “Upload”, o usuário será redirecionado para a funcionalidade de upload de imagens (Figura 8).

Funcionalidade para upload de imagens

Figura 8: Funcionalidade para upload de imagens

Ao se acionar a opção “Clique aqui para selecionar o(s) arquivo(s)”, será exibida uma janela para a escolha das imagens para pré-visualização (Figura 9).

Funcionalidade para upload de imagens

Figura 9: Funcionalidade para upload de imagens

Com os arquivos já selecionados, inicia-se a carga dos mesmos na pasta “PreVisualizacao”. Encerrado tal procedimento, uma mensagem será exibida em tela notificando isto (Figura 10); pressionando o botão OK, acontecerá então o redirecionamento para a pré-visualização das imagens (Figura 11).

Carregamento de imagens concluído

Figura 10: Carregamento de imagens concluído

Pré-visualização de imagens

Figura 11: Pré-visualização de imagens

O processo de upload das imagens será concluído ao se pressionar o botão “Confirmar”; ocorrerá assim o redirecionamento para a tela inicial do site, em que é possível observar desta vez que as imagens foram armazenadas com sucesso (Figura 12).

Imagens carregadas após o término do processo de upload

Figura 12: Imagens carregadas após o término do processo de upload

Conclusão

O plugin Uploadify é mais um exemplo de controle baseado em jQuery, combinando a esta biblioteca também o uso de Flash. Empregando recursos compatíveis com principais browsers, este componente permite que desenvolvedores das mais variadas plataformas possam tirar vantagens dos recursos oferecidos, simplificando com isto a implementação de funcionalidades que envolvam o upload de múltiplos arquivos simultaneamente.

Espero que conteúdo apresentado neste artigo possa lhe ser útil em algum momento. Até uma próxima oportunidade!