Exibir dados binários nos controles de dados da Web (C#)
por Scott Mitchell
Neste tutorial, analisamos as opções para apresentar dados binários em uma página da Web, incluindo a exibição de um arquivo de imagem e o provisionamento de um link 'Download' para um arquivo PDF.
Introdução
No tutorial anterior, exploramos as duas técnicas para associar dados binários a um modelo de dados subjacente de um aplicativo e usamos o controle FileUpload para carregar arquivos de um navegador para o sistema de arquivos do servidor Web. Ainda não vimos como associar os dados binários carregados ao modelo de dados. Ou seja, depois que um arquivo for carregado e salvo no sistema de arquivos, um caminho para o arquivo deverá ser armazenado no registro de banco de dados apropriado. Se os dados estiverem sendo armazenados diretamente no banco de dados, os dados binários carregados não precisarão ser salvos no sistema de arquivos, mas deverão ser injetados no banco de dados.
No entanto, antes de examinarmos como associar os dados ao modelo de dados, vamos primeiro examinar como fornecer os dados binários ao usuário final. Apresentar dados de texto é bastante simples, mas como os dados binários devem ser apresentados? Depende, é claro, do tipo de dados binários. Para imagens, provavelmente queremos exibir a imagem; para PDFs, documentos do Microsoft Word, arquivos ZIP e outros tipos de dados binários, fornecer um link de Download provavelmente é mais apropriado.
Neste tutorial, veremos como apresentar os dados binários junto com seus dados de texto associados usando controles da Web de dados como GridView e DetailsView. No próximo tutorial, voltaremos nossas atenções para associar um arquivo carregado ao banco de dados.
Etapa 1: fornecendoBrochurePath
valores
A Picture
coluna na Categories
tabela já contém dados binários para as várias imagens de categoria. Especificamente, a Picture
coluna de cada registro contém o conteúdo binário de uma imagem de bitmap granular, de baixa qualidade e de 16 cores. Cada imagem de categoria tem 172 pixels de largura e 120 pixels de altura e consome aproximadamente 11 KB. Além disso, o conteúdo binário na Picture
coluna inclui um cabeçalho OLE de 78 bytes que deve ser removido antes de exibir a imagem. Essas informações de cabeçalho estão presentes porque o banco de dados Northwind tem suas raízes no Microsoft Access. No Access, os dados binários são armazenados usando o tipo de dados Objeto OLE, que aborda esse cabeçalho. Por enquanto, veremos como remover os cabeçalhos dessas imagens de baixa qualidade para exibir a imagem. Em um tutorial futuro, criaremos uma interface para atualizar uma coluna de Picture
categoria e substituiremos essas imagens de bitmap que usam cabeçalhos OLE por imagens JPG equivalentes sem os cabeçalhos OLE desnecessários.
No tutorial anterior, vimos como usar o controle FileUpload. Portanto, você pode ir em frente e adicionar arquivos de folheto ao sistema de arquivos do servidor Web. No entanto, isso não atualiza a BrochurePath
coluna na Categories
tabela. No próximo tutorial, veremos como fazer isso, mas por enquanto precisamos fornecer valores manualmente para essa coluna.
No download deste tutorial, você encontrará sete arquivos de folheto PDF na ~/Brochures
pasta, um para cada uma das categorias, exceto Frutos do Mar. Omiti propositalmente a adição de um folheto de frutos do mar para ilustrar como lidar com cenários em que nem todos os registros têm dados binários associados. Para atualizar a Categories
tabela com esses valores, clique com o botão direito do Categories
mouse no nó do Servidor Explorer e escolha Mostrar Dados da Tabela. Em seguida, insira os caminhos virtuais para os arquivos de folheto para cada categoria que tenha um folheto, como mostra a Figura 1. Como não há nenhum folheto para a categoria Frutos do Mar, deixe o BrochurePath
valor da coluna como NULL
.
Figura 1: Insira manualmente os valores da Categories
coluna da BrochurePath
tabela (clique para exibir a imagem em tamanho real)
Etapa 2: Fornecendo um link de download para os folhetos em um GridView
Com os BrochurePath
valores fornecidos para a Categories
tabela, estamos prontos para criar um GridView que lista cada categoria junto com um link para baixar o folheto da categoria. Na Etapa 4, estenderemos este GridView para exibir também a imagem da categoria.
Comece arrastando um GridView da Caixa de Ferramentas para o Designer da DisplayOrDownloadData.aspx
página na BinaryData
pasta . Defina gridView s ID
como Categories
e por meio da marca inteligente GridView, escolha associá-lo a uma nova fonte de dados. Especificamente, associe-o a um ObjectDataSource chamado CategoriesDataSource
que recupera dados usando o CategoriesBLL
método do objeto.GetCategories()
Figura 2: Criar um novo objectDataSource chamado CategoriesDataSource
(clique para exibir a imagem em tamanho real)
Figura 3: Configurar o ObjectDataSource para usar a CategoriesBLL
classe (clique para exibir a imagem em tamanho real)
Figura 4: Recuperar a lista de categorias usando o GetCategories()
método (clique para exibir a imagem em tamanho real)
Depois de concluir o assistente Configurar Fonte de Dados, o Visual Studio adicionará automaticamente um BoundField ao Categories
GridView para , CategoryID
CategoryName
Description
, NumberOfProducts
, e BrochurePath
DataColumn
s. Vá em frente e remova BoundField NumberOfProducts
, pois a GetCategories()
consulta do método não recupera essas informações. Remova também BoundField CategoryID
e renomeie as CategoryName
propriedades e BrochurePath
BoundFields HeaderText
como Category e Brochure, respectivamente. Depois de fazer essas alterações, a marcação declarativa de GridView e ObjectDataSource deve ser semelhante à seguinte:
<asp:GridView ID="Categories" runat="server"
AutoGenerateColumns="False" DataKeyNames="CategoryID"
DataSourceID="CategoriesDataSource" EnableViewState="False">
<Columns>
<asp:BoundField DataField="CategoryName" HeaderText="Category"
SortExpression="CategoryName" />
<asp:BoundField DataField="Description" HeaderText="Description"
SortExpression="Description" />
<asp:BoundField DataField="BrochurePath" HeaderText="Brochure"
SortExpression="BrochurePath" />
</Columns>
</asp:GridView>
<asp:ObjectDataSource ID="CategoriesDataSource" runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetCategories" TypeName="CategoriesBLL">
</asp:ObjectDataSource>
Exiba esta página por meio de um navegador (consulte a Figura 5). Cada uma das oito categorias está listada. As sete categorias com BrochurePath
valores têm o BrochurePath
valor exibido no respectivo BoundField. Frutos do mar, que tem um NULL
valor para seu BrochurePath
, exibe uma célula vazia.
Figura 5: o nome, a descrição e o BrochurePath
valor de cada categoria são listados (clique para exibir a imagem em tamanho real)
Em vez de exibir o texto da BrochurePath
coluna, queremos criar um link para o folheto. Para fazer isso, remova BoundField e substitua-o BrochurePath
por um HyperLinkField. Defina a nova propriedade HyperLinkField como HeaderText
Brochure, sua Text
propriedade como View Brochure e sua DataNavigateUrlFields
propriedade como BrochurePath
.
Figura 6: Adicionar um HyperLinkField para BrochurePath
Isso adicionará uma coluna de links ao GridView, como mostra a Figura 7. Clicar em um link Exibir Folheto exibirá o PDF diretamente no navegador ou solicitará que o usuário baixe o arquivo, dependendo se um leitor de PDF está instalado e as configurações do navegador.
Figura 7: Um folheto de categoria pode ser exibido clicando no link Exibir Folheto (clique para exibir a imagem em tamanho real)
Figura 8: O PDF do Folheto da Categoria é exibido (clique para exibir a imagem em tamanho real)
Ocultando o texto do folheto de exibição para categorias sem um folheto
Como mostra a Figura 7, o BrochurePath
HyperLinkField exibe seu Text
valor de propriedade ( View Brochure ) para todos os registros, independentemente de haver um valor nãoNULL
para BrochurePath
. Claro, se BrochurePath
for NULL
, o link será exibido apenas como texto, como é o caso da categoria Frutos do Mar (consulte a Figura 7). Em vez de exibir o texto Folheto de Exibição, pode ser bom ter essas categorias sem um BrochurePath
valor exibindo algum texto alternativo, como Sem Folheto Disponível.
Para fornecer esse comportamento, precisamos usar um TemplateField cujo conteúdo é gerado por meio de uma chamada para um método de página que emite a saída apropriada com base no BrochurePath
valor . Primeiro, exploramos essa técnica de formatação no tutorial Usando TemplateFields no Controle GridView .
Transforme o HyperLinkField em um TemplateField selecionando o BrochurePath
HyperLinkField e clicando no link Converter este campo em um TemplateField na caixa de diálogo Editar Colunas.
Figura 9: Converter o HyperLinkField em um TemplateField
Isso criará um TemplateField com um ItemTemplate
que contém um controle Da Web HyperLink cuja NavigateUrl
propriedade está associada ao BrochurePath
valor . Substitua essa marcação por uma chamada para o método GenerateBrochureLink
, passando o valor de BrochurePath
:
<asp:TemplateField HeaderText="Brochure">
<ItemTemplate>
<%# GenerateBrochureLink(Eval("BrochurePath")) %>
</ItemTemplate>
</asp:TemplateField>
Em seguida, crie um protected
método na classe code-behind da página ASP.NET chamada GenerateBrochureLink
que retorna um string
e aceita um object
como um parâmetro de entrada.
protected string GenerateBrochureLink(object BrochurePath)
{
if (Convert.IsDBNull(BrochurePath))
return "No Brochure Available";
else
return string.Format(@"<a href="{0}">View Brochure</a>",
ResolveUrl(BrochurePath.ToString()));
}
Esse método determina se o valor passado object
é um banco de dados NULL
e, nesse caso, retorna uma mensagem indicando que a categoria não tem um folheto. Caso contrário, se houver um BrochurePath
valor, ele será exibido em um hiperlink. Observe que, se o BrochurePath
valor estiver presente, ele será passado para o ResolveUrl(url)
método . Esse método resolve a URL passada, substituindo o ~
caractere pelo caminho virtual apropriado. Por exemplo, se o aplicativo tiver raiz em /Tutorial55
, ResolveUrl("~/Brochures/Meats.pdf")
retornará /Tutorial55/Brochures/Meat.pdf
.
A Figura 10 mostra a página depois que essas alterações foram aplicadas. Observe que o campo da categoria Frutos do BrochurePath
Mar agora exibe o texto Sem Folheto Disponível.
Figura 10: o texto sem folheto disponível é exibido para essas categorias sem um folheto (clique para exibir a imagem em tamanho real)
Etapa 3: Adicionar uma página da Web para exibir uma imagem de categoria
Quando um usuário visita uma página ASP.NET, ele recebe o HTML da página ASP.NET. O HTML recebido é apenas texto e não contém dados binários. Quaisquer dados binários adicionais, como imagens, arquivos de som, aplicativos Macromedia Flash, vídeos Reprodutor Multimídia do Windows inseridos e assim por diante, existem como recursos separados no servidor Web. O HTML contém referências a esses arquivos, mas não inclui o conteúdo real dos arquivos.
Por exemplo, em HTML, o <img>
elemento é usado para fazer referência a uma imagem, com o src
atributo apontando para o arquivo de imagem da seguinte forma:
<img src="MyPicture.jpg" ... />
Quando um navegador recebe esse HTML, ele faz outra solicitação ao servidor Web para recuperar o conteúdo binário do arquivo de imagem, que ele então exibe no navegador. O mesmo conceito se aplica a qualquer dado binário. Na Etapa 2, o folheto não foi enviado para o navegador como parte da marcação HTML da página. Em vez disso, o HTML renderizado forneceu hiperlinks que, quando clicados, fizeram com que o navegador solicitasse o documento PDF diretamente.
Para exibir ou permitir que os usuários baixem dados binários que residem no banco de dados, precisamos criar uma página da Web separada que retorne os dados. Para nosso aplicativo, há apenas um campo de dados binário armazenado diretamente no banco de dados da imagem da categoria. Portanto, precisamos de uma página que, quando chamada, retorne os dados de imagem para uma categoria específica.
Adicione uma nova página ASP.NET à BinaryData
pasta chamada DisplayCategoryPicture.aspx
. Ao fazer isso, deixe a caixa de seleção Selecionar master página desmarcada. Esta página espera um CategoryID
valor na querystring e retorna os dados binários dessa coluna de categoria.Picture
Como esta página retorna dados binários e nada mais, ela não precisa de nenhuma marcação na seção HTML. Portanto, clique na guia Origem no canto inferior esquerdo e remova toda a marcação da página, exceto a <%@ Page %>
diretiva . Ou seja, DisplayCategoryPicture.aspx
a marcação declarativa deve consistir em uma única linha:
<%@ Page Language="C#" AutoEventWireup="true"
CodeFile="DisplayCategoryPicture.aspx.cs"
Inherits="BinaryData_DisplayCategoryPicture" %>
Se você vir o MasterPageFile
atributo na diretiva , remova-o <%@ Page %>
.
Na classe code-behind da página, adicione o seguinte código ao Page_Load
manipulador de eventos:
protected void Page_Load(object sender, EventArgs e)
{
int categoryID = Convert.ToInt32(Request.QueryString["CategoryID"]);
// Get information about the specified category
CategoriesBLL categoryAPI = new CategoriesBLL();
Northwind.CategoriesDataTable categories =
categoryAPI.GetCategoryWithBinaryDataByCategoryID(categoryID);
Northwind.CategoriesRow category = categories[0];
// Output HTTP headers providing information about the binary data
Response.ContentType = "image/bmp";
// Output the binary data
// But first we need to strip out the OLE header
const int OleHeaderLength = 78;
int strippedImageLength = category.Picture.Length - OleHeaderLength;
byte[] strippedImageData = new byte[strippedImageLength];
Array.Copy(category.Picture, OleHeaderLength,
strippedImageData, 0, strippedImageLength);
Response.BinaryWrite(strippedImageData);
}
Esse código começa lendo no CategoryID
valor de querystring em uma variável chamada categoryID
. Em seguida, os dados da imagem são recuperados por meio de uma chamada para o CategoriesBLL
método da classe.GetCategoryWithBinaryDataByCategoryID(categoryID)
Esses dados são retornados ao cliente usando o Response.BinaryWrite(data)
método , mas antes que isso seja chamado, o Picture
cabeçalho OLE do valor da coluna deve ser removido. Isso é feito criando uma byte
matriz chamada strippedImageData
que conterá precisamente 78 caracteres a menos do que o que está na Picture
coluna. O Array.Copy
método é usado para copiar os dados da category.Picture
posição 78 strippedImageData
para .
A Response.ContentType
propriedade especifica o tipo MIME do conteúdo que está sendo retornado para que o navegador saiba como renderizá-lo. Como a Categories
coluna da Picture
tabela é uma imagem bitmap, o tipo MIME de bitmap é usado aqui (image/bmp). Se você omitir o tipo MIME, a maioria dos navegadores ainda exibirá a imagem corretamente porque eles podem inferir o tipo com base no conteúdo dos dados binários do arquivo de imagem. No entanto, é prudente incluir o tipo MIME quando possível. Consulte o site da Autoridade de Números Atribuídos à Internet para obter uma listagem completa dos tipos de mídia MIME.
Com essa página criada, uma determinada imagem de categoria pode ser exibida visitando DisplayCategoryPicture.aspx?CategoryID=categoryID
. A Figura 11 mostra a imagem da categoria Bebidas, que pode ser exibida de DisplayCategoryPicture.aspx?CategoryID=1
.
Figura 11: a imagem da categoria bebidas é exibida (clique para exibir a imagem em tamanho real)
Se, ao visitar DisplayCategoryPicture.aspx?CategoryID=categoryID
, você receber uma exceção que lê Não é possível converter o objeto do tipo 'System.DBNull' para digitar 'System.Byte[]', há duas coisas que podem estar causando isso. Primeiro, a Categories
coluna da Picture
tabela permite NULL
valores. A DisplayCategoryPicture.aspx
página, no entanto, pressupõe que há um valor nãoNULL
presente. A Picture
propriedade do CategoriesDataTable
não poderá ser acessada diretamente se tiver um NULL
valor. Se você quiser permitir NULL
valores para a Picture
coluna, convém incluir a seguinte condição:
if (category.IsPictureNull())
{
// Display some "No Image Available" picture
Response.Redirect("~/Images/NoPictureAvailable.gif");
}
else
{
// Send back the binary contents of the Picture column
// ... Set ContentType property and write out ...
// ... data via Response.BinaryWrite ...
}
O código acima pressupõe que haja algum arquivo de imagem chamado NoPictureAvailable.gif
na Images
pasta que você deseja exibir para essas categorias sem uma imagem.
Essa exceção também poderá ser causada se a CategoriesTableAdapter
instrução s do SELECT
método s GetCategoryWithBinaryDataByCategoryID
tiver revertido para a lista de colunas da consulta main, o que pode acontecer se você estiver usando instruções SQL ad hoc e executar novamente o assistente para a consulta main do TableAdapter. Verifique se a GetCategoryWithBinaryDataByCategoryID
instrução do método s SELECT
ainda inclui a Picture
coluna .
Observação
Toda vez que o DisplayCategoryPicture.aspx
é visitado, o banco de dados é acessado e os dados de imagem da categoria especificada são retornados. No entanto, se a imagem da categoria não tiver sido alterada desde que o usuário a viu pela última vez, isso será um esforço desperdiçado. Felizmente, HTTP permite GETs condicionais. Com um GET condicional, o cliente que está fazendo a solicitação HTTP envia um If-Modified-Since
cabeçalho HTTP que fornece a data e hora em que o cliente recuperou esse recurso pela última vez do servidor Web. Se o conteúdo não tiver sido alterado desde essa data especificada, o servidor Web poderá responder com um código de status não modificado (304) e renunciar ao envio do conteúdo do recurso solicitado. Em suma, essa técnica aliviará o servidor Web de ter que enviar conteúdo de volta para um recurso se ele não tiver sido modificado desde a última vez que o cliente o acessou.
Para implementar esse comportamento, no entanto, exige que você adicione uma PictureLastModified
coluna à Categories
tabela a ser capturada quando a Picture
coluna foi atualizada pela última vez, bem como o código para marcar para o If-Modified-Since
cabeçalho. Para obter mais informações sobre o If-Modified-Since
cabeçalho e o fluxo de trabalho GET condicional, consulte HTTP Conditional GET for RSS Hackers and A Deeper Look at Performing HTTP Requests in an ASP.NET Page.
Etapa 4: Exibindo as imagens de categoria em um GridView
Agora que temos uma página da Web para exibir uma determinada imagem de categoria, podemos exibi-la usando o controle Web image ou um elemento HTML <img>
apontando para DisplayCategoryPicture.aspx?CategoryID=categoryID
. Imagens cuja URL é determinada por dados de banco de dados podem ser exibidas em GridView ou DetailsView usando o ImageField. O ImageField contém DataImageUrlField
propriedades e DataImageUrlFormatString
que funcionam como as propriedades e DataNavigateUrlFormatString
HyperLinkFieldDataNavigateUrlFields
.
Vamos aumentar o Categories
GridView adicionando DisplayOrDownloadData.aspx
um ImageField para mostrar a imagem de cada categoria. Basta adicionar o ImageField e definir suas DataImageUrlField
propriedades e DataImageUrlFormatString
como CategoryID
e DisplayCategoryPicture.aspx?CategoryID={0}
, respectivamente. Isso criará uma coluna GridView que renderiza um <img>
elemento cujo src
atributo faz referência a DisplayCategoryPicture.aspx?CategoryID={0}
, em que {0} é substituído pelo valor da CategoryID
linha GridView.
Figura 12: Adicionar um ImageField ao GridView
Depois de adicionar o ImageField, a sintaxe declarativa do GridView deve ter a seguinte aparência:
<asp:GridView ID="Categories" runat="server" AutoGenerateColumns="False"
DataKeyNames="CategoryID" DataSourceID="CategoriesDataSource"
EnableViewState="False">
<Columns>
<asp:BoundField DataField="CategoryName" HeaderText="Category"
SortExpression="CategoryName" />
<asp:BoundField DataField="Description" HeaderText="Description"
SortExpression="Description" />
<asp:TemplateField HeaderText="Brochure">
<ItemTemplate>
<%# GenerateBrochureLink(Eval("BrochurePath")) %>
</ItemTemplate>
</asp:TemplateField>
<asp:ImageField DataImageUrlField="CategoryID"
DataImageUrlFormatString="DisplayCategoryPicture.aspx?CategoryID={0}">
</asp:ImageField>
</Columns>
</asp:GridView>
Reserve um momento para exibir esta página por meio de um navegador. Observe como cada registro agora inclui uma imagem para a categoria.
Figura 13: a imagem da categoria é exibida para cada linha (clique para exibir a imagem em tamanho real)
Resumo
Neste tutorial, examinamos como apresentar dados binários. A forma como os dados são apresentados depende do tipo de dados. Para os arquivos de folheto PDF, oferecemos ao usuário um link Exibir Folheto que, quando clicado, levou o usuário diretamente para o arquivo PDF. Para a imagem da categoria, primeiro criamos uma página para recuperar e retornar os dados binários do banco de dados e, em seguida, usamos essa página para exibir cada imagem de categoria em um GridView.
Agora que analisamos como exibir dados binários, estamos prontos para examinar como executar inserções, atualizações e exclusões no banco de dados com os dados binários. No próximo tutorial, veremos como associar um arquivo carregado ao registro de banco de dados correspondente. No tutorial seguinte, veremos como atualizar os dados binários existentes, bem como excluir os dados binários quando seu registro associado for removido.
Programação feliz!
Sobre o autor
Scott Mitchell, autor de sete livros do ASP/ASP.NET e fundador da 4GuysFromRolla.com, trabalha com tecnologias da Microsoft Web desde 1998. Scott trabalha como consultor independente, treinador e escritor. Seu último livro é Sams Teach Yourself ASP.NET 2.0 em 24 Horas. Ele pode ser contatado em mitchell@4GuysFromRolla.com. ou através de seu blog, que pode ser encontrado em http://ScottOnWriting.NET.
Agradecimentos Especiais
Esta série de tutoriais foi revisada por muitos revisores úteis. Os principais revisores deste tutorial foram Teresa Murphy e Dave Gardner. Interessado em revisar meus próximos artigos do MSDN? Nesse caso, solte-me uma linha em mitchell@4GuysFromRolla.com.
Comentários
https://aka.ms/ContentUserFeedback.
Brevemente: Ao longo de 2024, vamos descontinuar progressivamente o GitHub Issues como mecanismo de feedback para conteúdos e substituí-lo por um novo sistema de feedback. Para obter mais informações, veja:Submeter e ver comentários