O NeoMatrix Tech está de casa nova!

Você deverá ser redirecionado em 6 segundos. Se não, visite:
http://www.leonelfraga.com/neomatrixtech
e atualize seus favoritos.

Aviso IMPORTANTÍSSIMO!

Aviso aos navegantes:

O NeoMatrix Tech mudou de casa!!!

A partir de agora, acessem pelo novo endereço:

http://www.leonelfraga.com/neomatrixtech

Ué... mas é só o domínio mudou de lugar?

R: Na verdade, não é bem assim hehe. Este domínio que você acessa agora aponta para um blog hospedado no Blogger, enquanto no novo, aponta para um blog na plataforma Wordpress, hospedagem própria, muito mais rápida e com um layout mais agradável de ler ;)

Não vou fechar este domínio igual ao que eu fiz com o NM Light (que já está 100% na nova plataforma). Talvez beeeeeeem depois eu faça isso.

Todos os posts daqui se encontram lá, e novos posts serão colocados somente no novo endereço.
A única coisa que não consegui importar foram os comentários. Mas em breve vai ter um post contando sobre a epopéia que foi migrar o NeoMatrix Tech!

Somente vou fechar a área de comentários daqui. Caso queiram comentar, favor ver o post correspondente no "Novo NeoMatrix Tech" e comentem por lá. É bem melhor! (pena que os permalinks "amigáveis para SEO" não funcionam lá, dá erro 404 e não consigo fazer a configuração funcionar. E olha que eu já vi vários artigos falando desse assunto :( ).

Quem assina o feed, já está lendo o conteúdo do novo NeoMatrix Tech!

sábado, 1 de novembro de 2008

Upload em ASP.NET com jqModal e Efeitos Ajax Pt. 3 -> Exibindo e fazendo download da foto do BD

Olá pessoal! Chegamos ao último artigo da série que ensina como fazer um upload de arquivo quando utilizamos o UpdatePanel do ASP.NET e janelas modais, porém sem perder a navegação no estilo AJAX (como é do nosso conhecimento, o FileUpload do ASP.NET necessita de um postback para ser executado).

Na primeira parte, foi explicado como fazemos um upload de um arquivo em janelas modais e UpdatePanel, utilizando iframes para manter a navegação no estilo AJAX e salvar o resultado do upload no sistema de arquivos do servidor; na segunda parte, como salvar esse arquivo em um banco de dados utilizando a Classe de Conexão e diretamente pelo provider do banco de dados (o Firebird é usado como exemplo).

Nesta terceira e última parte do tutorial, vou detalhar como exibimos em uma página e disponibilizamos para download esta foto que recuperamos do banco de dados.

Por incrível que pareça, esta é a parte mais simples de todas. Como todas as outras partes, assistam a vídeo-aula (screencast) e vejam a explicação em texto abaixo.

E os arquivos utilizados, podem ser obtidos na nossa página de suporte no final do artigo (cliquem no link para fazer o download)!


No artigo anterior, vimos que através de um comando SELECT trazemos para o nosso objeto TCadastro***** o campo BLOB que corresponde ao nosso arquivo, e que na classe ele é apenas um array de bytes sem distinção de formato, essas coisas. Isso na biblioteca de classes.

Na página Default.aspx do nosso exemplo, especialmente na janela modal dvEditarFoto temos um label que irá receber um comando HTML com a seguinte estrutura: <img src="visImagem.aspx?fid=xxx" ... /> e que no atributo src temos uma página .aspx que recebe em sua querystring o código da foto que iremos editar.

No exemplo deste artigo, temos algumas pequenas mudanças no design da página Default.aspx: No gridiview temos um botão que faz o download da foto, e em seu evento OnClick temos o registro da função JavaScript em Consts.Javascript.openWindow, que nada mais é que a montagem de um comando window.open, com a ajuda do registro da constante Consts.Javascript.ScriptPopUp no evento Page_Load. Ele abre a mesma página visImagem.aspx, porém recebendo outro parâmetro em sua querystring (d=1), além do ID da foto.

Também foi colocado uma tag <img> no gridview, que tem no seu atributo src a mesma página visImagem.aspx recebendo em sua querystring o ID da foto. Uma coisa interessante é a forma como eu monto essa tag <img> dentro da TemplateColumn do gridview:

Default.aspx.cs (Parcial)
   1: <asp:TemplateField>
   2:     <ItemTemplate>
   3:         <asp:Button runat="server" ID="btnEditar" Text="Editar" CommandArgument='<%#Bind("FotoID")%>' OnClick="btnEditar_Click" />
   4:         <asp:Button runat="server" ID="btnDownload" Text="Download" CommandArgument='<%#Bind("FotoID")%>' OnClick="btnDownload_Click" />
   5:         <asp:Button runat="server" ID="btnExcluir" Text="Excluir" CommandArgument='<%#Bind("FotoID")%>' OnClick="btnExcluir_Click" OnClientClick="return confirm('Deseja excluir?');"/>
   6:         <img runat="server" id="foto" src='<%#Bind("FotoID","visImagem.aspx?fid={0}")%>' alt="foto" width="50" height="50" />
   7:     </ItemTemplate>
   8: </asp:TemplateField>

Esta tag <img> possui o atributo runat="server", pois para alimentar a propriedade (sim, agora chamo assim exatamente por causa do runat="server" :-) ) utilizo-me da diretiva #Bind (que necessita que o controle onde vamos usar essa diretiva tenha o atributo runat="server" e consequentemente um ID), que no primeiro parâmetro recebe o nome do campo (ou propriedade da classe) que queremos que seja impresso na página e no segundo parâmetro uma string de formatação, que no nosso caso é "visImagem.aspx?fid={0}", onde "{0}" será substituído pelo ID da foto (por exemplo, você poderia usar aí qualquer string de formatação do .NET, como datas, moeda, etc, utilizando para isso "{0:<string de formatação do .NET>}", ex: "{0:dd/MM/yyyy}" para formatar uma data.

Como vocês já devem ter notado e se perguntado... o lance é a página visImagem.aspx, não é? Resposta: Sim, a própria!

Em ambos os casos (tanto visualizando a foto na página Default.aspx através do modal dvEditarFoto quanto na opção para download a página visImagem.aspx É o próprio arquivo de imagem que queremos recuperar. Mas como isso é feito, já que uma página .aspx é interpretada pelo compilador asp.net como uma página HTML?

Vou mostrar aqui apenas o code-behind da página visImagem.aspx, já que o design não possui componentes (possui somente as declarações do asp.net, tags head, html e body e a tag form). Isso mesmo, é só criar a página pelo Visual Studio e ir direto no code-behind :-)

visImagem.aspx.cs
   1: using System;
   2: using System.Data;
   3: using System.Configuration;
   4: using System.Collections;
   5: using System.Web;
   6: using System.Web.Security;
   7: using System.Web.UI;
   8: using System.Web.UI.WebControls;
   9: using System.Web.UI.WebControls.WebParts;
  10: using System.Web.UI.HtmlControls;
  11: using System.IO;
  12: using AppCore;
  13:  
  14: namespace UploadAJAX
  15: {
  16:     public partial class visImagem : System.Web.UI.Page
  17:     {
  18:         protected void Page_Load(object sender, EventArgs e)
  19:         {
  20:             if (Request.Params["fid"] != null)
  21:             {
  22:                 Response.Buffer = true;
  23:                 Response.ContentType = "image/jpeg";
  24:                 TCadastroClsConn cad = new TCadastroClsConn();
  25:                 try
  26:                 {
  27:                     cad.FotoID = Int32.Parse(Request.Params["fid"].ToString());
  28:                     if (cad.Foto.Length != 0)
  29:                     {
  30:                         string att = "inline";
  31:                         if (Request.Params["d"] != null)
  32:                         {
  33:                             att = "attachment";
  34:                         }
  35:                         
  36:                         Response.AddHeader("Content-Disposition", att + "; filename=foto" + cad.FotoID.ToString() + ".jpg");
  37:                         BinaryWriter bw = new BinaryWriter(Response.OutputStream);
  38:                         bw.Write(cad.Foto);
  39:                         bw.Flush();
  40:                         bw.Close();
  41:                     }
  42:                 }
  43:                 finally
  44:                 {
  45:                     cad.Dispose();
  46:                 }
  47:                 Response.End();
  48:             }
  49:         }
  50:     }
  51: }

A "transformação" de um arquivo .aspx em um arquivo qualquer (sim, este procedimento serve para recuperarmos QUALQUER tipo de arquivo) consiste em alterar o tipo de conteúdo no cabeçalho da resposta HTTP e colocarmos o arquivo desejado no stream de saída (o que vai para o navegador) da página.

No evento Page_Load, checamos se o parâmetro "fid" (que é informado na querystring) existe.

Setamos a propriedade Response.Buffer para true, isto indica que o que estiver no buffer de saída será enviado após processarmos a resposta (no nosso caso, com o método Response.End no final do evento Page_Load).

Como estamos trabalhando com imagens, e qualquer navegador hoje em dia trabalha com arquivos .jpg nativamente, colocamos no MIME type de resposta o valor "image/jpeg", que corresponde ao MIME type para arquivos .jpg. Isto é feito através da propriedade Response.ContentType.

Um parêntese aqui: E se o arquivo for um gif ou PNG? Neste caso, no banco de dados teríamos que gravar a extensão do arquivo que fizemos upload e precisaríamos de uma tabela auxiliar de MIME types, para setarmos a resposta corretamente. Mas como isso foge do escopo da série de artigos, deixo para você pensar um pouco :-)

Em seguida, instanciamos a classe TCadastroClsConn (poderia ser a sem a Classe de Conexão também), setando na propriedade FotoID o parâmetro "fid". Se o conteúdo da propriedade Foto (um array de bytes) for diferente de zero, vamos para o pulo do gato:

Criei uma variável chamada "att" do tipo string com o valor "inline". Se a querystring tiver um parâmetro chamado "d" ("d" de "Download"), não importando o valor, mudo essa variável para "attachment".

Explico: Logo na linha abaixo, inserimos no cabeçalho da resposta HTTP, através do método Response.AddHeader a chave "Content-Disposition", que indica como o navegador irá disponibilizar para o usuário o conteúdo que está sendo enviado pelo servidor web. Como valores possíveis, temos:

- inline: o conteúdo será disponibilizado através da área de visualização do navegador.
- attachment: o conteúdo será direcionado para o gerenciador de downloads do navegador.

Se o parâmetro "d" não existir na querystring, iremos enviar "inline", caso contrário, "attachment".

Como complemento do valor da chave "Content-Disposition", informo o atribiuto "filename", que será o nome do arquivo que irá aparecer no gerenciador de downloads do navegador quando baixamos esse arquivo.

Caso a opção seja por visualizar no navegador, ele irá renderizar o conteúdo que enviamos no stream de saída como um arquivo jpg (como informamos anteriormente no Response.ContentType), porém, quando vemos as propriedades desta imagem, vemos a URL que colocamos na tag <img> em Default.aspx, que é a própria página visImagem.aspx, como na imagem abaixo

screenshot-propfoto-firefox

Setamos como vai ser o tipo e a disposição do conteúdo de saída da página, agora só falta setar o conteúdo em si :-)

O que será enviado para o navegador do usuário está na propriedade Response.OutputStream do objeto Page (a própria página hehe). Ele é do tipo Stream.

Iremos colocar no OutputStream a foto que iremos enviar para o usuário, e ela é um array de bytes em que cada posição está cada byte do arquivo de foto. Para colocar este array de bytes no OutputStream, vamos fazer uso da classe BinaryWriter, que está no namespace System.IO, criando um objeto chamado "bw".

Ao instanciar a classe BinaryWriter no objeto bw, colocamos em seu construtor o stream de destino, que no nosso caso é o próprio Response.OutputStream. Em seguida, chamamos o método Write() do BinaryWriter que em uma das sobrecargas recebe como parâmetro um array de bytes (justo o tipo que estamos trabalhando :-) ); informamos neste parâmetro a propriedade Foto do nosso Cadastro (que por sua vez, irá buscar a foto que está em FotoID no banco de dados, através do método getRawFile, lembra?), para em seguida chamar o método Flush() e fecharmos o BinaryWriter.

Por fim, chamamos o método Response.End() que irá enfim enviar a foto para o usuário.

Este método serve para obtermos QUALQUER tipo de arquivo que gravamos em um banco de dados E não salvamos em hipótese alguma na estrutura de diretórios do servidor web. Pode ser foto, mp3, pdf, enfim, qualquer um, bastando informar o MIME type correto no Response.ContentType, e tomar cuidado ao usar os meios "inline" e "attachment" dependendo do tipo de arquivo, por exemplo, para .exe usar o meio "attachment".

Fácil, não foi?

Um abraço a todos, e até o próximo artigo (quem sabe... não vamos aprender a gerar um thumbnail através da imagem que gravamos no BD?)!

Upload com efeito AJAX usando jQuery Pt. 3 (221 KiB)

0 comentários:


Postar um comentário

Para tornar este artigo ainda mais interessante, escreva suas críticas (desde que construtivas e sem ofenças), elogios, sugestões, complementos, dúvidas, etc, etc, etc!!!

Sobre o NeoMatrix Tech

Meu blog para assuntos profissionais, ligado com tecnologia.
Dicas de programação (grande parte de C# e ASP.NET, mas não limitado a essa plataforma :-) ), dicas de utilitários, análises de equipamentos e serviços, resenhas sobre sites que eu visito, relacionados com tecnologia, opinião sobre mercado de trabalho, metodologias de desenvolvimento, comportamento no mundo tecnológico...

NeoMatrix Light

  © Blogger templates ProBlogger Template by Ourblogtemplates.com 2008 - Editado e configurado por Leonel F.

Voltar ao TOPO