Multi-Upload com ASP.NET usando JQuery e escrita na sessão do Handler

Apesar do título grande e, para uns, confuso, nesse tópico irei ajudar muitos a resolver um problema: múltiplos uploads de vez sem precisar selecionar cada arquivo.



A idéia primordial é fazer com que o usuário possa clicar em um botão, selecionar vários arquivos de vez (que nem o GMail) e fazer o envio para uma pasta desejada. Para isso iremos utilizar um Handler em C# para fazer o upload. Mas nesse mesmo Handler irei escrever na sessão para que possa utilizar em outra página. Lembrando que as variáveis de sessão, para usar dentro de um Handler precisa-se de um artifício. Sem mais delongas, vamos à solução.

Crie ou abra um Web Site Project e nele adicione um Generic Handler. Coloque com o nome Upload.ashx para ficar mais fácil de encontrá-lo. Insira o seguinte cógido:

using System;
using System.Data;
using System.IO;
using System.Web;
using System.Web.SessionState;

public class Upload : IHttpHandler, IRequiresSessionState{

        public void ProcessRequest (HttpContext context) {
                context.Response.ContentType = "text/plain";
                context.Response.Expires = -1;
                try
                {
                        // Obtêm o arquivo a ser postado
                        HttpPostedFile postedFile = context.Request.Files["filedata"];
                        // Caminho
                        string path = context.Server.MapPath("~/Upload/");
                        string filename = postedFile.FileName;
                        // Cria diretório de não existir
                        if (!Directory.Exists(path))
                                Directory.CreateDirectory(path);
                        // Verifica se o arquivo já existe com mesmo nome
                        string nome = filename.Substring(0, filename.LastIndexOf("."));
                        string extensao = filename.Substring(filename.LastIndexOf(".") + 1);
                        int i = 1;
                        // Verifica se existe, senão renomeia
                        while (File.Exists(path + @"\" + filename))
                        {
                                filename = nome + "(" + i + ")." + extensao;
                                i++;
                        }
                        // Adiciona na sessão
                        DataTable galeria = (DataTable)context.Session["galeria"];
                        DataRow item = galeria.NewRow();
                        item["imagem"] = filename;
                        galeria.Rows.Add(item);
                        context.Session["galeria"] = galeria;
                        // Salva arquivo
                        postedFile.SaveAs(path + @"\" + filename);
                        // Retorna o arquivo salvo
                        context.Response.Write(path + "/" + filename);
                        context.Response.StatusCode = 200;
                }
                catch (Exception ex)
                {
                        context.Response.Write("Erro: " + ex.Message);
                }
        }


        public bool IsReusable {
                get {
                       return true;
                }
        }

}
 
Pronto! Já temos nosso Handler que faz o upload de um arquivo e o adiciona em um DataTable. Esse DataTable já estava previamente adicionado na sessão. Você pode utilizar quaisquer outra estrutura para armazenar. A dica da escrita na sessão no Handler está na herança da interface IRequiresSessionState onde permitirá fazer isso.
 
Crie uma página ASPX e referencie os JavaScripts do JQuery abaixo (os arquivos, caso não possuam, irei disponibilizar em um link abaixo) e um CSS pra dar um estilo legal:

<link rel="stylesheet" type="text/css" href="css/stilo.css" />
<script type="text/javascript" src="js/jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="js/jquery.uploadify.js"></script>

Agora adicione um controle FileUpload e um link (ou um controle HyperLink). Iremos também fazer a chamada do JQuery para ser aplicado sobre o FileUpload ficando dessa forma:

<asp:FileUpload ID="Fotos" runat="server" />
<input type="button" onclick="javascript:$('#<%=Fotos.ClientID%>').fileUploadStart();" value="Enviar" />
<script type="text/javascript">
$(window).load(
       function() {
       $("#<%=Fotos.ClientID %>").fileUpload({
           'uploader': 'js/uploader.swf',
           'cancelImg': 'imagens/cancelar.png',
           'buttonText': 'Selecionar',
           'script': 'Upload.ashx',
           'folder': 'Upload',
           'fileDesc': 'Selecione arquivos do tipo imagem',
           'fileExt': '*.jpg;*.jpeg;*.gif;*.png',
           'multi': true,
           'auto': false
       });
      }
);
</script>

Agora rode a aplicação. Verá apenas um botão com o nome Selecionar. Ao clicar irá abrir um pop-up pedindo para selecionar os arquivos. Selecione um ou mais e clique em OK. Verá que será montado uma lista com os arquivos que irão ser enviados. Você poderá remover itens clicando no X sobre cada um deles. Ao clicar no link Enviar, será feito uma chamada para cada item sobre o Handler fazendo o envio para a pasta Upload e adicionando no DataTable armazenado na sessão.

Não vou entrar muito em datelhes, porque está bem fácil e compreensível o código. Se desejar, ao invés de clicar em Enviar para fazer o envio, você pode deixar automático (como se fosse uma trigger) mudando o parâmetro 'auto' para true da chamada JQuery. Então, ao selecionar e clicar em OK automaticamente será feito o upload. Se também quiser que o link faça um PostBack na página, basta colocar depois da chamada de início do upload, insira o __doPostBack('',''); colocando parâmetro ou não dependendo do que for fazer com ele após.

Nesse link aqui encontram-se alguns arquivos necessários para que possam utilizar. Não vou colocar os fontes ASP.NET porque senão já seria demais, né? Mãos à obra...

Obs: a fonte e outras matérias sobre o mesmo tópico você acha aí pela net. Não me lembro qual site eu havia visto algo do tipo e fiz essa. Mas fica a dica aí!