Desenvolvimento - ASP. NET
Armazenando imagens do SQL Server com ASP.NET
Aprenda a construir uma aplicação ASP.NET para armazenar imagens no SQL Server utilizando o Visual C#.NET.
por Carlos de MattosUma necessidade comum nas aplicações Web é o armazenamento de imagens. Existem várias formas para realizarmos esta tarefa. O SQL Server oferece um tipo de dado ideal para esta necessidade - o tipo Image - com ele você pode armazenar imagens nos mais diversos formatos (GIF, BMP, JPG, etc). Neste artigo, você aprenderá todos os passos necessários para implementar uma aplicação ASP.NET utilizando o Visual Basic.NET e o Visual C#.NET que permitirá ao usuário gravar, ler e excluir imagens no SQL Server.
Estrutura do banco de dados
Crie um novo banco de dados no SQL Server 2000 ou utilize seu banco de dados de testes para implementar a tabela tabImagens. Esta tabela armazenará além da própria imagem, uma descrição, o tamanho e o tipo de arquivo de imagem. A Listagem 1 apresenta o script necessário para criar a tabela.
if exists (select * from sysobjects where name like "%tabImagens%") drop table tabImagens go create table tabImagens ( ImagemID int IDENTITY (1,1) not null, Descricao nvarchar(200), Imagem image, Tamanho int, Tipo nvarchar(200) ) go create unique index tabImagens_ImagemID on tabImagens ( ImagemID ) go alter table tabImagens add primary key (ImagemID) go
Listagem 1: Script da tabela tabImagens
Nota: O arquivo contendo o script completo para implementação desta tabela e das stored procedures necessárias para a conclusão do exemplo apresentado neste artigo está disponível para download no site da Fórum juntamente com todos os arquivos que compõem a solução.
Stored procedures
Nosso aplicativo de exemplo deverá permitir ao usuário adicionar e excluir imagens em nosso banco de dados, consultar uma lista das imagens armazenadas e visualizar as imagens individualmente. Para facilitar a codificação e ganhar performance, as instruções SQL necessárias para esses processos serão transformadas em procedimentos armazenados (stored procedures). A Listagem 2 apresenta o código necessário para implementação desses procedimentos.
if exists (select * from sysobjects where name like "%spAdicionarImagem%") drop proc spAdicionarImagem go create proc spAdicionarImagem( @Descricao nvarchar(200), @Imagem image, @Tamanho int, @Tipo nvarchar(200) ) as insert into tabImagens(Descricao,Imagem,Tamanho,Tipo) values(@Descricao,@Imagem,@Tamanho,@Tipo) go /*======================================================================*/ if exists (select * from sysobjects where name like "%spListarImagens%") drop proc spListarImagens go create proc spListarImagens as select ImagemID, Descricao, Tamanho, Tipo from tabImagens order by Descricao go /*======================================================================*/ if exists (select * from sysobjects where name like "%spExibirImagem%") drop proc spExibirImagem go create proc spExibirImagem( @ImagemID int ) as select * from tabImagens where ImagemID = @ImagemID go /*======================================================================*/ if exists (select * from sysobjects where name like "%spExcluirImagem%") drop proc spExcluirImagem go create proc spExcluirImagem( @ImagemID int ) as delete from tabImagens where ImagemID = @ImagemID go
Listagem 2: Os procedimentos armazenados
Construindo a página para adicionar imagens no SQL
A primeira página que construiremos é aquela que permitirá ao usuário adicionar imagens no banco de dados. Utilizando o Visual Studio.NET, crie um novo projeto utilizando o template ASP.NET Web Application e modifique o nome do WebForm1 para Gravar_Imagem.aspx. Adicione uma tabela para organizar os controles que serão utilizados na página. Vamos trabalhar com um controle TextBox onde o usuário colocará a descrição da imagem, um controle HTML File Field que será utilizado para indicarmos o arquivo de imagem, um Button que invocará o procedimento para gravar a imagem e um LinkButton que exibirá a página Listar_Imagens.aspx.
Quero chamar a atenção do leitor para o controle HTML File Field. Quando inserimos esse controle no WebForm através da Caixa de Ferramentas o parâmetro RUNAT não está definido. É necessário adicionar esse parâmetro e atribuir o valor SERVER para que possamos fazer referências às propriedades e métodos do controle em nosso código. A Listagem 3 apresenta o código HTML necessário para implementar todos os controles.
<TABLE id="Table1">Listagem 3: O código HTML para a página Gravar_Imagem.aspx.A interface da página Gravar_Imagem.aspx é mostrada na Figura 1.
Figura 1: A interface da página Gravar_Imagem.aspxAs classes System.DataÉ importante lembrar o leitor que neste exemplo utilizaremos três WebForms (Gravar_Imagem.aspx, Listar_Imagens.aspx e Exibir_Imagem.aspx). Como em todos eles implementaremos rotinas de acesso à dados armazenados no SQL Server, o leitor deve adicionar à seção de declarações (no topo da janela de código) as referências as Classes System.Data e System.Data.SqlClient, como mostra A Listagem 4.
using System.Data; using System.Data.SqlClient;
Listagem 4: Referência as classes de dadosCodificando o botão cmdGravarImagem
A principal função da página Gravar_Imagem.aspx está associada ao evento click do botão cmdGravarImagem. Esse procedimento de evento será responsável por obter as informações do arquivo de imagem através do controle HTML File Field e passá-las para o stored procedure que efetivará a gravação no banco de dados. A Listagem 5 apresenta o código necessário para esse procedimento.
private void cmdGravarImagem_Click(object sender, System.EventArgs e) { // esta string armazenará o tipo de imagem (JPEG, BMP, GIF, etc) // o controle html <input type=file> fornecerá esta informação string strTipo = fileImagemParaGravar.PostedFile.ContentType; // o tamanho do arquivo de imagem também é fornecido pelo mesmo controle // e armazenado na variável intTamanho int intTamanho = System.Convert.ToInt32(fileImagemParaGravar.PostedFile.InputStream.Length); // a variável byteImagem é um array com tamanho estabelecido pela propriedade // length que foi armazenada na variável intTamanho (tamanho do arquivo em bytes) byte[] byteImagem = new byte[intTamanho]; // o método Read() do controle File se encarregará de ler o arquivo de imagem // e armazenar o conteúdo na variável byteImagem. A sintaxe deste método é: // Read(<variável>, início, fim) fileImagemParaGravar.PostedFile.InputStream.Read(byteImagem,0,intTamanho); // esta variável armazenará a string para conexão com o SQL Server // para facilitar nosso trabalho, a string de conexão foi armazenada // numa variável de aplicação. Desta forma, podemos invocá-la sempre que // necessário e em caso de alteração das informações de conexão, precisaremos // atualizar apenas o arquivo Global.asax string cnString = "Data Source=localhost;UID=sa;PWD=;Initial Catalog=SQLImage"; SqlConnection Connection = new SqlConnection(cnString); // criamos o objeto Command e definimos suas propriedades, ele será utilizado // para invocar a StoredProcedure que gravará a imagem no SQL Server SqlCommand Command = new SqlCommand(); Command.Connection = Connection; Command.CommandType = CommandType.StoredProcedure; Command.CommandText = "spAdicionarImagem"; // adicionamos o parâmetro @Descricao à coleção de parâmetros do objeto Command SqlParameter prmDescricao = new SqlParameter("@Descricao", SqlDbType.NVarChar); prmDescricao.Value = txtDescricao.Text; Command.Parameters.Add(prmDescricao); // adicionamos o parâmetro @Imagem à coleção de parâmetros do objeto Command SqlParameter prmImagem = new SqlParameter("@Imagem", SqlDbType.Image); prmImagem.Value = byteImagem; Command.Parameters.Add(prmImagem); // adicionamos o parâmetro @Tamanho à coleção de parâmetros do objeto Command SqlParameter prmImagemTamanho = new SqlParameter("@Tamanho", SqlDbType.Int); prmImagemTamanho.Value = intTamanho; Command.Parameters.Add(prmImagemTamanho); // adicionamos o parâmetro @Tipo à coleção de parâmetros do objeto Command SqlParameter prmImagemTipo = new SqlParameter("@Tipo", SqlDbType.NVarChar); prmImagemTipo.Value = strTipo; Command.Parameters.Add(prmImagemTipo); // abrimos a conexão, executamos o Command e fechamos a conexão Connection.Open(); Command.ExecuteNonQuery(); Connection.Close(); // limpa a caixa de texto txtDescricao txtDescricao.Text = ""; }
Listagem 5: Código do botão cmdGravarImagemEntendendo como funciona o Upload da imagem
A chave para o funcionamento deste procedimento está nas propriedades e métodos do controle HTML File Field. Através dele podemos obter o path e nome do arquivo; o tamanho e o tipo de imagem; e, invocando o método Read() associado às propriedades PostedFile e InputStream, podemos alimentar nosso array de bytes que representa a imagem. Esse array é passado para o parâmetro @Imagem do nosso procedimento armazenado que efetivará a gravação da imagem no banco de dados.
O LinkButton
A única função do LinkButton inserido na página Gravar_Imagem.aspx é invocar outro WebForm: a página Listar_Imagens.aspx, que apresentará a lista de imagens gravadas no banco de dados. Para configurar esse controle utilize a Tabela 1 como referência.
Propriedade | Valor |
Name | lnkExibirImagens |
NavigateUrl | Listar_Imagens.aspx |
Target | _Blank |
Tabela 1: Propriedades do controle LinkButton
A página Listar_Imagens.aspx
Adicione um novo WebForm ao projeto e dê o nome Listar_Imagens.aspx. A função desta página é exibir uma lista com todas as imagens gravadas no SQL Server, informando o Código, Descrição, Tamanho e Tipo de imagem. Além disso a página deverá prover um link para visualizar a imagem e outro para permitir ao usuário excluir imagens do banco de dados. Para implementar essas funcionalidades, utilizaremos um controle DataGrid. A Listagem 6 mostra o código necessário para a configuração adequada do controle DataGrid.
<asp:datagrid id="dgImagens" runat="server" AutoGenerateColumns="False" OnDeleteCommand="ExcluirImagem"> <Columns> <asp:BoundColumn DataField="ImagemID" ReadOnly="True" HeaderText="Código"> <HeaderStyle Font-Bold="True" HorizontalAlign="Center"></HeaderStyle> <ItemStyle HorizontalAlign="Center"></ItemStyle> </asp:BoundColumn> <asp:BoundColumn DataField="Descricao" ReadOnly="True" HeaderText="Descrição"> <HeaderStyle Font-Bold="True" HorizontalAlign="Center"></HeaderStyle> </asp:BoundColumn> <asp:BoundColumn DataField="Tamanho" ReadOnly="True" HeaderText="Tamanho (Bytes)"> <HeaderStyle Font-Bold="True" HorizontalAlign="Center"></HeaderStyle> <ItemStyle HorizontalAlign="Center"></ItemStyle> </asp:BoundColumn> <asp:BoundColumn DataField="Tipo" ReadOnly="True" HeaderText="Tipo"> <HeaderStyle Font-Bold="True" HorizontalAlign="Center"></HeaderStyle> </asp:BoundColumn> <asp:HyperLinkColumn Text="<IMG alt="Exibir Imagem" border="0" src="../../images/magnify.gif">" Target="_blank" DataNavigateUrlField="ImagemID" DataNavigateUrlFormatString="exibir_imagem.aspx?ImagemID={0}" HeaderText="Exibir"> <HeaderStyle Font-Bold="True" HorizontalAlign="Center"></HeaderStyle> <ItemStyle HorizontalAlign="Center"></ItemStyle> </asp:HyperLinkColumn> <asp:ButtonColumn Text="<IMG alt="Excluir Imagem" border="0" src="../../images/error.gif">" HeaderText="Excluir" CommandName="Delete"> <HeaderStyle Font-Bold="True" HorizontalAlign="Center"></HeaderStyle> <ItemStyle HorizontalAlign="Center"></ItemStyle> </asp:ButtonColumn> </Columns> <PagerStyle Mode="NumericPages"></PagerStyle> </asp:datagrid>
Listagem 6: O DataGrid para exibir a lista de imagensAs Colunas do DataGrid
O controle DataGrid é muito versátil e uma poderosa ferramenta que pode ser utilizada em diversas situações. Neste exemplo, trabalhamos com três tipos de colunas: BoundColumn, HyperLinkColumn e ButtonColumn. As colunas do tipo BoundColumn serão utilizadas para exibir as informações extraídas do banco de dados (Codigo, Descrição, Tamanho e Tipo). A coluna do tipo HyperLinkColumn será utilizada para exibir um link para visualização da imagem. A coluna do tipo ButtonColumn será utilizada para exibir um botão que invocará o procedimento para exclusão de uma imagem no banco de dados. Como o leitor pode verificar nA Listagem 5, ao contrário de trabalharmos com texto nas colunas do tipo HyperLinkColumn e ButtonColumn, utilizamos imagens. Esta prática é comum e bastante fácil de aplicar, basta substituir o texto que seria exibido no botão ou no hyperlink por um tag HTML <IMG>. Observe o resultado produzido na Figura 2.
Figura 2: A página Listar_Imagens.aspx
Codificando a página Listar_Imagens.aspx
Com um duplo-clique no corpo do WebForm você terá acesso à janela de código que exibirá o procedimento do evento Load da página. Modifique esse procedimento para invocar a rotina que alimentará o DataGrid. A Listagem 7 apresenta o código associado ao procedimento do evento Load.
private void Page_Load(object sender, System.EventArgs e) { ListarImagens(); }
Listagem 7: O procedimento do evento Load
A rotina ListarImagens
Esse procedimento estabelece uma conexão com o banco de dados, dispara um procedimento armazenado através de um objeto SqlCommand e utiliza-o para alimentar um objeto SqlDataReader que servirá de fonte de dados para nosso controle DataGrid. Como mostra A Listagem 8.
private void ListarImagens() { // esta variável armazenará a string para conexão com o SQL Server // para facilitar nosso trabalho, a string de conexão foi armazenada // numa variável de aplicação. Desta forma, podemos invocá-la sempre que // necessário e em caso de alteração das informações de conexão, precisaremos // atualizar apenas o arquivo Global.asax string cnString = "Data Source=localhost;UID=sa;PWD=;Initial Catalog=SQLImage"; SqlConnection Connection = new SqlConnection(cnString); Connection.Open(); // criamos o objeto Command e definimos suas propriedades, ele será utilizado // para invocar a StoredProcedure que gravará a imagem no SQL Server SqlCommand Command = new SqlCommand(); Command.Connection = Connection; Command.CommandType = CommandType.StoredProcedure; Command.CommandText = "spListarImagens"; // cria o objeto SqlDataReader e carrega-o com os dados obtidos SqlDataReader DataReader; DataReader = Command.ExecuteReader(); // atribui o objeto SqlDataReader à origem de dados do DataGrid dgImagens.DataSource = DataReader; dgImagens.DataBind(); Connection.Close(); }
Listagem 8: O procedimento ListarImagens()
O procedimento ExcluirImagem
Esse procedimento estabelece uma conexão com o banco de dados, invoca o procedimento armazenado para exclusão da imagem e, após a exclusão, atualiza o DataGrid. O leitor deve observar que esse procedimento é disparado sempre que o usuário clica na figura da coluna ButtonColumn. Isso ocorre porque essa coluna possui uma propriedade chamada CommandName cujo valor atribuido é igual a "Delete" e o DataGrid, por sua vez, possui um Gerenciador de Evento chamado "OnDeleteCommand" cujo valor atribuído é o nome do procedimento "ExcluirImagem" (Ver Listagem 6). Assim, quando a imagem é clicada, o DataGrid recebe a notificação que o evento Delete foi disparado e invoca o procedimento associado a ele. A Listagem 9 apresenta o código do procedimento ExcluirImagem.
protected void ExcluirImagem(Object sender, DataGridCommandEventArgs e) { // estabelecemos a conexão string cnString = "Data Source=localhost;UID=sa;PWD=;Initial Catalog=SQLImage"; SqlConnection Connection = new SqlConnection(cnString); Connection.Open(); // criamos o objeto command SqlCommand Command = new SqlCommand(); Command.Connection = Connection; Command.CommandType = CommandType.StoredProcedure; Command.CommandText = "spExcluirImagem"; // adicionamos o parâmetro @Descricao à coleção de parâmetros do objeto Command SqlParameter prmImagemID = new SqlParameter("@ImagemID", SqlDbType.Int); prmImagemID.Value = e.Item.Cells[0].Text; Command.Parameters.Add(prmImagemID); // disparamos o commando para excluir a imagem Command.ExecuteNonQuery(); Connection.Close(); // invocamos a rotina ListarImagens para atualizar o DataGrid ListarImagens(); }
Listagem 9: O procedimento ExcluirImagem()
Visualizando as imagens
Para finalizar nosso exemplo, vamos implementar a página Exibir_Imagem.aspx. A única função desta página é exibir a imagem selecionada na lista da página Listar_Imagens.aspx. O processo utilizado é semelhante ao processo de upload da imagem. Desta vez, utilizaremos o objeto Response para indicar qual é o tipo de informação que enviaremos para o browser do internauta, isto será feito através da propriedade ContentType do objeto Response. E, através do método Write() associado a propriedade OutputStream faremos uma leitura binária do conteúdo armazenado no banco de dados que será enviado diretamente para o browser. Sabendo a natureza do conteúdo (informada através da propriedade ContentType) o browser exibe a imagem com sucesso. A Figura 3 mostra uma imagem sendo visualizada através deste WebForm.
Figura 3: Visualizando imagens
Codificando a página Exibir_Imagem.aspx
No evento Load desta página adicione uma chamada para o procedimento ExibirImagem(), como mostra A Listagem 10.
private void Page_Load(object sender, System.EventArgs e) { ExibirImagem(); }
Listagem 10: O evento Load
O procedimento ExibirImagem
Esse procedimento é responsável por estabelecer a conexão, obter o registro correspondente à imagem selecionada e enviar o conteúdo binário da coluna Imagem para o browser do cliente. A Listagem 11 apresenta o código deste procedimento.
private void ExibirImagem() { // estabelece a conexão string cnString = "Data Source=localhost;UID=sa;PWD=;Initial Catalog=SQLImage"; SqlConnection cn = new SqlConnection(cnString); cn.Open(); // cria o objeto SqlCommand SqlCommand cmd = new SqlCommand(); cmd.Connection = cn; cmd.CommandType = CommandType.StoredProcedure; cmd.CommandText = "spExibirImagem"; // adiciona o parâmetro @ImagemID obtido através da variável de URL SqlParameter prmImagemID = new SqlParameter("@ImagemID", SqlDbType.Int); prmImagemID.Value = Request.QueryString["ImagemID"]; cmd.Parameters.Add(prmImagemID); // cria o objeto SqlDataReader e alimenta-o com a respectiva imagem SqlDataReader dr; dr = cmd.ExecuteReader(); dr.Read(); // utiliza o objeto Response para enviar o conteúdo para o browser Response.ContentType = dr["Tipo"].ToString(); Response.OutputStream.Write((byte[])dr["Imagem"], 0, System.Convert.ToInt32(dr["Tamanho"])); cn.Close(); }
Listagem 11: O procedimento ExibirImagem
Conclusão
Você acompanhou neste artigo os passos necessários para implementar uma aplicação que permitirá o armazenamento e gerenciamento de imagens no SQL Server.
Para se Aprofundar
Consulte também os links abaixo para obter informações complementares:
ASP.NET Developer Center
http://www.msdn.microsoft.com/asp.net/
Visual C#.NET Developer Center
http://www.msdn.microsoft.com/vcsharp/