Upload em ASP.NET com jqModal e efeitos AJAX
Olá pessoal! Agpora sim, retornando às dicas de programação, nesta série de 3 artigos mostrarei como fazer um upload em uma página ASP.NET que utiliza os componentes AJAX, ou seja, tem um UpdatePanel.
Neste primeiro artigo, será mostrado como fazer o upload de um arquivo em uma janela modal construída pelo plugin jqModal do jQuery. E isso sem perder a navegação nas janelas modais. Salvaremos o arquivo na estrutura de diretórios do servidor web.
No segundo artigo, vamos salvar este arquivo em um banco de dados, tanto utilizando a Classe de Conexão quanto fazendo as instruções SQL "na mão".
No terceiro e último artigo, vamos recuperar este arquivo do banco de dados e exibí-lo em tela após o upload, da mesma forma que o Orkut faz quando atualizamos uma foto do perfi.
Esta será uma vídeo-aula acompanhada da explicação em texto, abaixo dos vídeos. Como o o limite de tempo de cada vídeo no YouTube é de dez minutos, precisei dividir a vídeo-aula em três vídeos, já que ela dura em torno de 23 minutos. No site exibirei no player a primeira parte do vídeo, e abaixo dele os links para as duas partes restantes.
Como dito no vídeo, o componente FileUpload nativo do ASP.NET 2.0 não funciona se ele estiver contido em um UpdatePanel. Mas, como os sites fazem upload com AJAX?
Há diversas formas de fazer isso, seja com componentes pagos ou gratuítos. Não posso falar sobre estes componentes pois não cheguei a testá-los. No nosso tutorial, não utilizaremos nenhum componente externo ao .NET Framework (pelo menos na parte de servidor, já que iremos usar biblioteca JS :-) ), faremos uma espécie de "gambi" e fazer com que o nosso diálogo de upload tenha visual de AJAX :-)
Lembrando que o exemplo está na página de suporte no final deste post do NM Tech!!!
Construiremos duas páginas em nosso projeto web, uma chamada "Default.aspx" e outra chamada "uploadFile.aspx". Vejam a seguir o código XHTML do design:
1: <%@ Page Language="C#" AutoEventWireup="true" Codebehind="Default.aspx.cs" Inherits="UploadAJAX._Default" %>
2:
3: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
4: <html xmlns="http://www.w3.org/1999/xhtml">
5: <head runat="server">
6: <title>Exemplo de Upload com ASP.NET, jqModal e efeitos AJAX</title>
7: <link rel="stylesheet" href="css/jqModal.css" />
8:
9: <script type="text/javascript" src="javascript/jquery-1.2.6.pack.js"></script>1:
2:
3: <script type="text/javascript" src="javascript/jqModal.js">1: </script>
2: <style type="text/css">3: .invisivel
4: {
5: visibility:hidden;
6: }
7: </style>
8: </head>
9: <body>
10: <form id="form1" runat="server">11: <asp:ScriptManager ID="ScriptManager1" runat="server" />12: <asp:UpdatePanel runat="server" ID="Upd1">13: <ContentTemplate>
14: <div>
15: <span>Página de Teste de Upload com Efeitos AJAX</span>
16: <input type="button" value="Chamar Janela Modal" onclick="$dvUplModal.jqmShow();return false;" />17: <input type="button" id="btnSinalizaUpload" onclick="<%=btnSalvar.ClientID%>.click()" style="visibility: hidden;" />18: </div>
19: </ContentTemplate>
20: </asp:UpdatePanel>
21: <div id="dvUplModal" class="jqmWindow">22: <asp:UpdatePanel runat="server" ID="Upd2"><ContentTemplate>23: <span>Aqui iremos solicitar o arquivo</span>
24: <iframe src="uploadFile.aspx" style="border: none 0px; overflow: hidden; height: 50px;25: width: 100%"></iframe>
26: <input type="button" value="Fechar Janela" onclick="$dvUplModal.jqmHide(); return false;" />27: <asp:Button runat="server" ID="btnSalvar" Text="Salvar definitivamente" CssClass="invisivel" OnClick="btnSalvar_Click" />28: </ContentTemplate></asp:UpdatePanel>
29: </div>
30:
31: <script type="text/javascript">32: //Inicializa o Modal33: var $dvUplModal = $('#dvUplModal').jqm({modal:true,toTop:true,trigger:false});34:
</script>
10:
11: </form>
12: </body>
13: </html>
1: <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="uploadFile.aspx.cs" Inherits="UploadAJAX.uploadFile" %>
2:
3: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
4:
5: <html xmlns="http://www.w3.org/1999/xhtml" >
6: <head runat="server">
7: <title>Untitled Page</title>
8: </head>
9: <body>
10: <form id="form1" runat="server">
11: <div>
12: <asp:ScriptManager ID="ScriptManager1" runat="server" />
13: <div id="dvUpload" style="width: 100%">
14: <asp:FileUpload runat="server" ID="fuArq" CssClass="tbx-normal" Width="300px" />
15: <asp:Button runat="server" ID="btnCarregar" Text="Carregar Arquivo" CssClass="botoes"
16: OnClick="btnCarregar_Click" OnClientClick="Upload();" /><br />
17: <asp:Label runat="server" ID="lbInfo" CssClass="fonte-peq" Text=""></asp:Label>
18: </div>
19: <div id="dvCarregar" style="display: none;">
20: <img src="imagens/progresso_carga.gif" alt="Aguarde, carregando arquivo" />
21: </div>
22:
23: <script type="text/javascript">1:
2: function Upload()3: {
4: $get("dvUpload").style.display = 'none';5: $get("dvCarregar").style.display = 'block';6: }
7:
8: function SinalizaUpload()9: {
10: if(parent.document.getElementById("btnSinalizaUpload") != null)11: {
12: parent.document.getElementById("btnSinalizaUpload").click();13: }
14: }
15:
</script>
24: </div>
25: </form>
26: </body>
27: </html>
Na página Default.aspx, temos as declarações do jQuery e plugins, uma classe CSS chamada "invisivel" e 2 divs principais:
- o div dentro do UpdatePanel "Upd1", onde temos dois botões HTML, sendo um que chama a janela modal representada pelo div "dvUplModal" e outro botão invisível, "btnSinalizaUpload", que irá disparar o evento onClick do botão btnSalvar, dentro do div dvUplModal.
- o div dvUplModal, que contém dois botões, sendo um HTML que irá fechar o dvUplModal através do método jqmHide() do jqModal e outro botão ASP.NET (btnSalvar) que irá disparar uma rotina no servidor, representado pelo evento OnClick do mesmo.
E também temos um iframe, cuja página no atributo src é a nossa uploadFile.aspx. Formatamos esse iframe para que suas bordas não apareçam na página. É dentro deste iframe que ficará o componente FileUpload.
Para finalizar a página Default.aspx temos um bloco JavaScript que faz a inicialização da janela modal representada pelo div dvUplModal, colocando a referência do mesmo na variável $dvUplModal.
Na página uploadFile.aspx temos o seguinte:
- o div dvUpload, onde fica o componente FileUpload (fuArq) e um botão que irá carregar este arquivo (btnCarregar) através de seu evento onClick de servidor (método btnCarregar_Click) e dispara a função JavaScript Upload() em seu evento onClick no browser.
- o div dvCarregar, que contém uma imagem que representa uma barra de progresso. Ela é um gif animado, feito através do site www.ajaxload.info
No bloco JavaScript desta página, temos duas funções interessantes e fundamentais para a mágica do upload com AJAX funcionar:
- Função Upload(): Quando clicamos no botão btnCarregarArquivo, o arquivo é postado para o servidor web. Neste instante, o div em que está contido o FileUpload é oculto e o div contendo o gif animado representando o "progresso" da operação é exibido.
Lembre-se que o FileUpload está dentro de um iframe que é exibido em uma janela modal. Então, quando o upload estiver sendo executado, o usuário irá ver o gif animado durante o post da página e o browser não irá sair da página Default.aspx, mesmo quando o post for concluído.
- Função SinalizaUpload(): Esta rotina é disparada quando o post da página for concluído, através de um comando RegisterStartupScript dentro do método btnCarregar_Click no code-behind de fileUpload.aspx. Caso exista um botão chamado btnSinalizaUpload existir na página em que está contido o nosso iframe (o comando parent.document representa a página contêiner) o seu evento onClick cliente será executado. No nosso caso, a página Default.aspx é o contênier do iframe.
A cobra começou a fumar agora né? Veja bem o fluxo da operação:
- Usuário chama a página modal em Default.aspx
- Depois, seleciona um arquivo através da página fileUpload em um iframe dentro da janela modal
- É feito o post da página e é exibido um gif animado para o usuário
- Com o post concluído, é disparado a função JavaScript SinalizaUpload() em uploadFile.aspx.
- Esta função, chama o evento onClick de btnSinalizaUpload na página Default.aspx
- Este evento onClick, por sua vez, chama o evento OnClick de btnSalvar, em Default.aspx
- O arquivo é processado e salvo no disco.
Mas... você não poderia ter chamado diretamente o evento onClick do botão btnSalvar de Default.aspx?
Sim, poderia, mas veja bem: Para salvarmos o arquivo no disco, precisamos utilizar uma rotina no servidor, que somente pode ser disparada por um controle de servidor ASP.NET, e o nosso btnSinalizaUpload é um controle HTML comum. Se tivéssemos utilizado master pages, o nosso btnSalvar gerará um ID HTML meio esquisito, algo como ctl00_<alguma coisa> o que é difícil de prevermos. Para controles HTML, isso não acontece (desde que não tenha o atributo runat="server").
Como precisamos do ID no browser do botão em outra página (na função SinalizaUpload() em uploadFile.aspx), convém escolher um que saibamos o nome. Por isso essa jogada, pois como necessitamos executar uma rotina de um controle que não sabemos o nome que o ASP.NET designará a ele no navegador, façamos com que um controle que saibamos o nome dispare tal rotina.
Agora, vamos ver como é feita a "transferência" do arquivo da nossa página uploadFile.aspx (que está em um iframe) para ser processado na página Default.aspx. Veja o code-behind das páginas Default.aspx e uploadFile.aspx:
1: public partial class _Default : System.Web.UI.Page
2: {
3: protected void Page_Load(object sender, EventArgs e)
4: {
5:
6: }
7:
8: protected void btnSalvar_Click(object sender, EventArgs e)
9: {
10: string msg = "";
11: if (Session["AREA_UPLOAD"] != null)
12: {
13: try
14: {
15: string fPath = this.MapPath("/") + "\\UploadedFiles\\" + Session["FILE_NAME"].ToString();
16: FileStream fs = new FileStream(fPath, FileMode.CreateNew);
17: fs.Write((byte[])Session["AREA_UPLOAD"], 0, (Session["AREA_UPLOAD"] as byte[]).Length);
18: fs.Flush();
19: fs.Close();
20: fs.Dispose();
21: msg = "Upload concluído com sucesso :-)";
22: Session.Remove("AREA_UPLOAD");
23: Session.Remove("FILE_NAME");
24: }
25: catch(Exception ex)
26: {
27: msg = "Erro no upload -> " + ex.Message.Replace("'","");
28: }
29: }
30: string script = String.Format("alert('{0}');", msg);
31: script += "$dvUplModal.jqmHide();";
32: ScriptManager.RegisterStartupScript(this, this.GetType(), "alerta",script , true);
33: }
34: }
1: public partial class uploadFile : System.Web.UI.Page
2: {
3: protected void Page_Load(object sender, EventArgs e)
4: {
5: if (!IsPostBack)
6: {
7: if (Session["AREA_UPLOAD"] != null)
8: {
9: Session.Remove("AREA_UPLOAD");
10: }
11: }
12: }
13:
14: //Upload do arquivo para uma variável de sessão, para ser utilizada dentro de outras páginas
15: protected void btnCarregar_Click(object sender, EventArgs e)
16: {
17: string script = "";
18: if (fuArq.FileBytes.Length > 0)
19: {
20:
21: if (Session["AREA_UPLOAD"] != null)
22: {
23: Session.Remove("AREA_UPLOAD");
24: Session.Remove("FILE_NAME");
25: }
26: Session.Add("AREA_UPLOAD", fuArq.FileBytes);
27: Session.Add("FILE_NAME", fuArq.FileName);
28: lbInfo.Text = "Arquivo carregado: " + fuArq.FileName;
29: script += "SinalizaUpload();";
30: Thread.Sleep(10000);
31: }
32: else
33: {
34: if (Session["AREA_UPLOAD"] != null)
35: {
36: Session.Remove("AREA_UPLOAD");
37: }
38: script += "SinalizaUpload();";
39: }
40: ScriptManager.RegisterStartupScript(this, this.GetType(), "sinalizar", script, true);
41: }
42: }
Vamos começar pela página uploadFile.aspx, que onde o primeiro código de servidor é executado.
No evento Page_Load checamos a existência de uma variável de sessão chamada "AREA_UPLOAD", que será onde iremos guardar temporariamente o arquivo a ser carregado. Se ela existir, removemos-a para ter a certeza de que nenhum arquivo de sessão anterior esteja lá.
O evento btnCarregar_Click é que fará o trabalho sujo: Caso o tamanho em bytes do arquivo seja maior que zero (ou seja, há um arquivo com conteúdo postado), removemos mais uma vez as variáveis de sessão caso elas existam.
Após isso, adicionamos o conteúdo do arquivo (propriedade FileBytes de fuArq) na variável de sessão AREA_UPLOAD, que será tratada na página Default.aspx. Também guardamos o nome do arquivo na variável de sessão FILE_NAME.
Feito tudo isso, registramos a função JavaScript SinalizaUpload para que o código do botão de salvamento de Default.aspx seja executado.
Caso não tenha arquivo, removemos a variável de sessão AREA_UPLOAD e sinalizamos para a rotina de salvamento em Default.aspx.
Na página Default.aspx, no evento OnClick do botão btnSalvar é executada a rotina de salvamento em disco. Pegamos o path físico da raíz do nosso servidor web, através do método MapPath do objeto Page e adicionamos o complemento do nome do arquivo: a pasta "UploadedFiles" e o nome do arquivo, na variável de sessão FileName.
Em seguida criamos um objeto do tipo FileStream, passando em seu construtor o path completo do arquivo e o modo de criação, no caso estamos criando um novo arquivo. Chamamos o método Write() do FileStream, que recebe como parâmetros um array de bytes com o conteúdo do arquivo. Como as variáveis de sessão retornam sempre Object, faremos um unboxing para recuperar o array de bytes que o componente FileUpload da página uploadFile.aspx nos retornou. Também devemos informar a posição incial do array que iremos escrever e por fim a quantidade de bytes, que no nosso caso pegamos da variável de sessão AREA_UPLOAD fazendo um cast da mesma para o tipo byte[] e usando a propriedade Length.
Por fim, finalizamos o FileStream e disparamos um alert em JavaScript para o usuário e fechamos a janela modal do upload.
Pareceu complexo, não é? Mas quando você for replicar este exemplo verá que foi bem simples :-)
Exemplo Upload com efeito AJAX, usando jqModal (45KiB)
Um abraço e aguardem a próxima parte deste artigo!
0 comentários:
Postar um comentário