Compartilhar via


Exibir dados binários nos controles de dados da Web (VB)

por Scott Mitchell

Baixar PDF

Neste tutorial, examinamos 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 fornecimento de um link 'Download' para um arquivo PDF.

Introdução

No tutorial anterior, exploramos as duas técnicas para associar dados binários ao 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 é carregado e salvo no sistema de arquivos, um caminho para o arquivo deve 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.

Antes de examinarmos a associação dos dados ao modelo de dados, no entanto, 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 Web de dados como GridView e DetailsView. No próximo tutorial, voltaremos nossa atenção para associar um arquivo carregado ao banco de dados.

Etapa 1: FornecendoBrochurePathvalores

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 granulada e de baixa qualidade 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 OLE Object, que se aproxima desse 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 da categoria e substituiremos essas imagens de bitmap que usam cabeçalhos OLE por imagens JPG equivalentes sem os cabeçalhos Picture OLE desnecessários.

No tutorial anterior, vimos como usar o controle FileUpload. Portanto, você pode ir em frente e adicionar arquivos de brochura 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 manualmente os valores para essa coluna.

No download deste tutorial, você encontrará sete arquivos de brochuras em 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 mouse no Categories nó do Gerenciador de Servidores e escolha Mostrar Dados da Tabela. Em seguida, insira os caminhos virtuais para os arquivos de folhetos para cada categoria que tenha um folheto, como mostra a Figura 1. Como não há brochura para a categoria Frutos do mar, deixe o BrochurePath valor da coluna como NULL.

Insira manualmente os valores da coluna BrochurePath da tabela de categorias

Figura 1: Inserir manualmente os valores da coluna da BrochurePath tabela (clique para exibir a Categories imagem em tamanho real)

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 esse 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 o GridView s ID para Categories e por meio da marca inteligente do GridView, opte por 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 GetCategories() objeto.

Criar um novo ObjectDataSource chamado CategoriesDataSource

Figura 2: Criar um novo ObjectDataSource chamado CategoriesDataSource (clique para exibir a imagem em tamanho real)

Configurar o ObjectDataSource para usar a classe CategoriesBLL

Figura 3: Configurar o ObjectDataSource para usar a classe (clique para exibir a CategoriesBLL imagem em tamanho completo)

Recupere a lista de categorias usando o método GetCategories()

Figura 4: Recuperar a lista de categorias usando o método (clique para exibir a GetCategories() imagem em tamanho real)

Depois de concluir o assistente Configurar Fonte de Dados, o Categories Visual Studio adicionará automaticamente um BoundField ao GridView para o CategoryID, CategoryName, Description, NumberOfProductse BrochurePath DataColumn s. Vá em frente e remova o NumberOfProducts BoundField, pois a GetCategories() consulta do método não recupera essas informações. Remova também o CategoryID BoundField e renomeie as CategoryName propriedades e BrochurePath BoundFields HeaderText para Category e Brochure, respectivamente. Depois de fazer essas alterações, a marcação declarativa do GridView e do 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>

Visualize esta página por meio de um navegador (consulte a Figura 5). Cada uma das oito categorias é 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.

O nome, a descrição e o valor de BrochurePath de cada categoria estão listados

Figura 5: O nome, a descrição e BrochurePath o valor de cada categoria estão listados (clique para exibir a imagem em tamanho real)

Em vez de exibir o BrochurePath texto da coluna, queremos criar um link para o folheto. Para fazer isso, remova o BrochurePath BoundField e substitua-o por um HyperLinkField. Defina a nova propriedade do HeaderText HyperLinkField como Brochura, sua Text propriedade como Exibir Brochura e sua DataNavigateUrlFields propriedade como BrochurePath.

Adicionar um HyperLinkField para 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.

Um folheto de categoria pode ser exibido clicando no link Exibir folheto

Figura 7: Um folheto de categoria pode ser exibido clicando no link Exibir folheto (clique para exibir a imagem em tamanho real)

O PDF do folheto da categoria é exibido

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 não-NULL valor para BrochurePath. Obviamente, 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 Exibir Brochura, pode ser bom fazer com que essas categorias sem um BrochurePath valor exibam algum texto alternativo, como Nenhuma Brochura 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. Exploramos essa técnica de formatação pela primeira vez 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.

Converta o HyperLinkField em um TemplateField

Figura 9: Converter o HyperLinkField em um TemplateField

Isso criará um TemplateField com um ItemTemplate que contém um controle 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 Function GenerateBrochureLink(BrochurePath As Object) As String
    If Convert.IsDBNull(BrochurePath) Then
        Return "No Brochure Available"
    Else
        Return String.Format("<a href="{0}">View Brochure</a>", _
            ResolveUrl(BrochurePath.ToString()))
    End If
End Function

Esse método determina se o valor passado é um banco de dados NULL e, em Object caso afirmativo, 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 estiver enraizado em /Tutorial55, ResolveUrl("~/Brochures/Meats.pdf") retornará /Tutorial55/Brochures/Meat.pdf.

A Figura 10 mostra a página após a aplicação dessas mudanças. Observe que o campo da categoria Frutos BrochurePath do mar agora exibe o texto Nenhum folheto disponível.

O texto Nenhum folheto disponível é exibido para as categorias sem folheto

Figura 10: O texto Nenhum folheto disponível é exibido para as categorias sem um folheto (clique para exibir a imagem em tamanho real)

Etapa 3: Adicionando uma página da Web para exibir uma imagem da 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 incorporados do Windows Media Player 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 é exibido no navegador. O mesmo conceito se aplica a quaisquer dados binários. 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 fornecia hiperlinks que, quando clicados, faziam 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, a imagem da categoria. Portanto, precisamos de uma página que, quando chamada, retorne os dados da imagem para uma determinada categoria.

Adicione uma nova página ASP.NET à BinaryData pasta chamada DisplayCategoryPicture.aspx. Ao fazer isso, deixe a caixa de seleção Selecionar página mestra desmarcada. Esta página espera um CategoryID valor na querystring e retorna os dados binários dessa coluna da Picture categoria. 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 Fonte 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 de s deve consistir em uma única linha:

<%@ Page Language="VB" AutoEventWireup="true" 
    CodeFile="DisplayCategoryPicture.aspx.vb" 
    Inherits="BinaryData_DisplayCategoryPicture" %>

Se você vir o MasterPageFile atributo na <%@ Page %> diretiva, remova-o.

Na classe code-behind da página, adicione o seguinte código ao Page_Load manipulador de eventos:

Protected Sub Page_Load(sender As Object, e As EventArgs) Handles Me.Load
    Dim categoryID As Integer = _
        Convert.ToInt32(Request.QueryString("CategoryID"))
    ' Get information about the specified category
    Dim categoryAPI As New CategoriesBLL()
    Dim categories As Northwind.CategoriesDataTable = _
        categoryAPI.GetCategoryWithBinaryDataByCategoryID(categoryID)
    Dim category As Northwind.CategoriesRow = 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 OleHeaderLength As Integer = 78
    Dim strippedImageLength As Integer = _
        category.Picture.Length - OleHeaderLength
    Dim strippedImageData(strippedImageLength) As Byte
    Array.Copy(category.Picture, OleHeaderLength, _
        strippedImageData, 0, strippedImageLength)
    Response.BinaryWrite(strippedImageData)
End Sub

Esse código começa lendo o valor da CategoryID 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 GetCategoryWithBinaryDataByCategoryID(categoryID) classe. Esses dados são retornados ao cliente usando o Response.BinaryWrite(data) método, mas antes de ser 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 Picture que está na coluna. O Array.Copy método é usado para copiar os dados da category.Picture posição 78 para strippedImageData.

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 tabela é uma imagem de Picture 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 Internet Assigned Numbers Authority para obter uma lista completa dos tipos de mídia MIME.

Com esta página criada, a imagem de uma determinada categoria pode ser visualizada visitando DisplayCategoryPicture.aspx?CategoryID=categoryID. A Figura 11 mostra a imagem da categoria Bebidas, que pode ser visualizada em DisplayCategoryPicture.aspx?CategoryID=1.

A imagem da categoria de bebidas é exibida

Figura 11: A imagem da categoria de bebidas é exibida (clique para exibir a imagem em tamanho real)

Se, ao visitar DisplayCategoryPicture.aspx?CategoryID=categoryIDo , você receber uma exceção que diz Não é possível converter o objeto do tipo 'System.DBNull' para o tipo '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, assume que há um não-valorNULL presente. A Picture propriedade do CategoriesDataTable não pode ser acessada diretamente se tiver um NULL valor. Se você quiser permitir NULL valores para a Picture coluna, inclua a seguinte condição:

If category.IsPictureNull() Then
    ' 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 ...
End If

O código acima pressupõe que há algum arquivo de imagem nomeado 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 do SELECT método s GetCategoryWithBinaryDataByCategoryID tiver sido revertida para a lista de colunas da consulta principal, o que pode acontecer se você estiver usando instruções SQL ad hoc e tiver executado novamente o assistente para a consulta principal do TableAdapter. Verifique se GetCategoryWithBinaryDataByCategoryID a instrução do SELECT método ainda inclui a Picture coluna.

Observação

Sempre 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 a última vez que o usuário a visualizou, isso será um esforço desperdiçado. Felizmente, o HTTP permite GETs condicionais. Com um GET condicional, o cliente que faz a solicitação HTTP envia um If-Modified-Since cabeçalho HTTP que fornece a data e a 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 de volta do conteúdo do recurso solicitado. Em resumo, essa técnica alivia o servidor web de ter que enviar de volta o conteúdo de um recurso se ele não tiver sido modificado desde a última vez que o cliente o acessou.

Para implementar esse comportamento, no entanto, é necessário adicionar uma PictureLastModified coluna à Categories tabela para capturar quando a Picture coluna foi atualizada pela última vez, bem como código para verificar 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 e Uma análise mais profunda da execução de solicitações HTTP em uma página ASP.NET.

Etapa 4: Exibindo as imagens de categoria em um GridView

Agora que temos uma página da Web para exibir uma imagem de categoria específica, podemos exibi-la usando o controle Image Web ou um elemento HTML <img> apontando para DisplayCategoryPicture.aspx?CategoryID=categoryID. As imagens cuja URL é determinada pelos dados do banco de dados podem ser exibidas no GridView ou no DetailsView usando o ImageField. O ImageField contém DataImageUrlField propriedades e DataImageUrlFormatString que funcionam como as propriedades e DataNavigateUrlFields DataNavigateUrlFormatString HyperLinkField.

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 cujas src referências DisplayCategoryPicture.aspx?CategoryID={0}de atributo , onde {0} é substituído pelo valor da CategoryID linha GridView.

Adicionar um ImageField ao GridView

Figura 12: Adicionar um ImageField ao GridView

Depois de adicionar o ImageField, a sintaxe declarativa do GridView deve ser semelhante a acalmar o 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: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 visualizar esta página por meio de um navegador. Observe como cada registro agora inclui uma imagem para a categoria.

A imagem da categoria é exibida para cada linha

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 brochura em PDF, oferecemos ao usuário um link Exibir brochura que, quando clicado, levava o usuário diretamente ao 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 da categoria em um GridView.

Agora que vimos 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 depois disso, veremos como atualizar os dados binários existentes, bem como excluir os dados binários quando seu registro associado for removido.

Boa programação!

Sobre o autor

Scott Mitchell, autor de sete livros ASP/ASP.NET e fundador da 4GuysFromRolla.com, trabalha com tecnologias da Web da Microsoft desde 1998. Scott trabalha como consultor, instrutor e escritor independente. 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 a

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? Em caso afirmativo, envie-me uma mensagem para mitchell@4GuysFromRolla.com.