Dela via


Visa binära data i datawebbkontrollerna (C#)

av Scott Mitchell

Ladda ned PDF

I den här självstudien tittar vi på alternativen för att presentera binära data på en webbsida, inklusive visning av en bildfil och tillhandahållande av en nedladdningslänk för en PDF-fil.

Inledning

I föregående självstudie utforskade vi de två teknikerna för att associera binära data med ett programs underliggande datamodell och använde FileUpload-kontrollen för att ladda upp filer från en webbläsare till webbserverns filsystem. Vi har ännu inte sett hur du associerar uppladdade binära data med datamodellen. När en fil har laddats upp och sparats i filsystemet måste en sökväg till filen lagras i lämplig databaspost. Om data lagras direkt i databasen behöver de uppladdade binära data inte sparas i filsystemet, utan måste matas in i databasen.

Innan vi tittar på hur du associerar data med datamodellen ska vi dock först titta på hur du tillhandahåller binära data till slutanvändaren. Det är enkelt att presentera textdata, men hur ska binära data presenteras? Det beror naturligtvis på typen av binära data. För bilder vill vi förmodligen visa bilden. För PDF-filer, Microsoft Word-dokument, ZIP-filer och andra typer av binära data är det förmodligen lämpligare att tillhandahålla en nedladdningslänk.

I den här självstudien tittar vi på hur du presenterar binära data tillsammans med tillhörande textdata med hjälp av datawebbkontroller som GridView och DetailsView. I nästa självstudie fokuserar vi på att associera en uppladdad fil med databasen.

Steg 1: AngeBrochurePathvärden

Kolumnen Picture i Categories tabellen innehåller redan binära data för de olika kategoribilderna. Picture Mer specifikt innehåller kolumnen för varje post det binära innehållet i en kornig bitmappsbild med låg kvalitet och 16 färger. Varje kategoribild är 172 bildpunkter bred och 120 bildpunkter hög och förbrukar ungefär 11 kB. Dessutom innehåller det binära innehållet i Picture kolumnen ett OLE-huvud på 78 byte som måste tas bort innan bilden visas. Den här rubrikinformationen finns eftersom Northwind-databasen har sina rötter i Microsoft Access. I Access lagras binära data med datatypen OLE-objekt, som lägger till denna header. För tillfället ser vi hur du tar bort rubrikerna från dessa bilder av låg kvalitet för att visa bilden. I en framtida självstudie kommer vi att skapa ett gränssnitt för att uppdatera en kategorikolumn och ersätta dessa bitmappsbilder Picture som använder OLE-huvuden med motsvarande JPG-avbildningar utan onödiga OLE-huvuden.

I den föregående guiden såg vi hur man använder kontrollen FileUpload. Därför kan du lägga till broschyrfiler i webbserverns filsystem. Detta gör dock inte att kolumnen BrochurePath uppdateras i tabellen Categories. I nästa självstudie får vi se hur du gör detta, men för tillfället måste vi manuellt ange värden för den här kolumnen.

I den här självstudien finns sju PDF-broschyrfiler i ~/Brochures mappen, en för var och en av kategorierna utom Seafood. Jag utelämnade avsiktligt att lägga till en Seafood-broschyr för att illustrera hur man hanterar scenarier där inte alla poster har associerade binära data. Om du vill uppdatera Categories tabellen med dessa värden högerklickar du på noden från ServerUtforskaren Categories och väljer Visa tabelldata. Ange sedan de virtuella sökvägarna till broschyrfilerna för varje kategori som har en broschyr, som bild 1 visar. Eftersom det inte finns någon broschyr för kategorin Fisk och skaldjur lämnar du kolumnens BrochurePath värde som NULL.

Ange värdena för kolumnen Categories Table s BrochurePath manuellt

Bild 1: Ange värden för Categories tabellens BrochurePath kolumn manuellt (Klicka om du vill visa en bild i full storlek)

Med de BrochurePath värden som anges för Categories tabellen är vi redo att skapa en GridView som visar varje kategori tillsammans med en länk för att ladda ned kategoribroschyren. I steg 4 utökar vi den här GridView för att även visa kategorins bild.

Börja med att dra en GridView från verktygslådan till sidan Designer DisplayOrDownloadData.aspx i BinaryData mappen. Ange GridView s ID till Categories och via GridViews smarta tagg, välj att binda den till en ny datakälla. Mer specifikt binder du den till en ObjectDataSource med namnet CategoriesDataSource som hämtar data med hjälp av CategoriesBLL objektmetoden GetCategories() .

Skapa en ny ObjectDataSource med namnet CategoriesDataSource

Bild 2: Skapa en ny ObjectDataSource med namnet CategoriesDataSource (Klicka om du vill visa en bild i full storlek)

Konfigurera ObjectDataSource för att använda CategoriesBLL-klassen

Bild 3: Konfigurera ObjectDataSource att använda CategoriesBLL klassen (Klicka om du vill visa en bild i full storlek)

Hämta listan över kategorier med metoden GetCategories()

Bild 4: Hämta listan över kategorier med hjälp GetCategories() av metoden (Klicka om du vill visa en bild i full storlek)

När du har slutfört guiden Konfigurera datakälla lägger Visual Studio automatiskt till ett BoundField i Categories GridView för CategoryID, CategoryName, Description, NumberOfProductsoch BrochurePathDataColumn s. Ta bort NumberOfProducts BoundField eftersom GetCategories() metodens fråga inte hämtar den här informationen. Ta också bort CategoryID BoundField och byt namn på CategoryName och BrochurePath BoundFields HeaderText egenskaper till Kategori respektive Broschyr. När du har gjort dessa ändringar bör din GridView- och ObjectDataSource-deklarativa markering se ut så här:

<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>

Visa den här sidan via en webbläsare (se bild 5). Var och en av de åtta kategorierna visas. De sju kategorierna med BrochurePath värden har värdet BrochurePath som visas i respektive BoundField. Seafood, som har ett NULL värde för sin BrochurePath, visar en tom cell.

Varje kategoris namn, beskrivning och BrochurePath-värde visas

Bild 5: Varje kategoris namn, beskrivning och BrochurePath värde visas (Klicka om du vill visa en bild i full storlek)

I stället för att visa texten i BrochurePath kolumnen vill vi skapa en länk till broschyren. För att åstadkomma detta tar du bort BrochurePath BoundField och ersätter det med ett HyperLinkField. Ange den nya HyperLinkField-egenskapen HeaderText till Broschyr, dess Text egenskap till Visa Broschyr och dess DataNavigateUrlFields egenskap till BrochurePath.

Lägga till ett HyperLinkField för BrochurePath

Bild 6: Lägg till ett HyperLinkField för BrochurePath

Då läggs en kolumn med länkar till GridView, som bild 7 visar. Om du klickar på länken Visa broschyr visas pdf-filen direkt i webbläsaren eller uppmanar användaren att ladda ned filen, beroende på om en PDF-läsare är installerad och webbläsarens inställningar.

Du kan visa en kategoribroschyr genom att klicka på länken Visa broschyr

Bild 7: En kategoribroschyr kan visas genom att klicka på länken Visa broschyr (Klicka om du vill visa en bild i full storlek)

Den kategoriens PDF-broschyr visas

Bild 8: Pdf-filen för kategorins broschyr visas (Klicka om du vill visa en bild i full storlek)

Dölj broschyrtexten för kategorier utan broschyr

Som visas i bild 7, visar BrochurePath HyperLinkField dess Text egenskapsvärde ( Visa broschyr ) för alla poster, oavsett om det finns ett icke-NULL värde för BrochurePath. Naturligtvis, om BrochurePath är NULL, så visas länken endast som text, vilket också är fallet med kategorin Seafood (se bild 7). I stället för att visa texten Visa broschyr kan det vara trevligt att ha dessa kategorier utan ett BrochurePath värde som visar en alternativ text, till exempel Ingen broschyr tillgänglig.

För att kunna tillhandahålla det här beteendet måste vi använda ett TemplateField vars innehåll genereras via ett anrop till en sidmetod som genererar lämpliga utdata baserat på BrochurePath värdet. Vi utforskade först den här formateringstekniken tidigare i självstudiekursen om att använda TemplateFields i GridView-kontrollen.

Omvandla HyperLinkField till ett TemplateField genom att BrochurePath välja HyperLinkField och sedan klicka på länken Konvertera det här fältet till en TemplateField-länk i dialogrutan Redigera kolumner.

Konvertera HyperLinkField till ett TemplateField

Bild 9: Konvertera HyperLinkField till ett TemplateField

Då skapas ett TemplateField med en ItemTemplate som innehåller en HyperLink-webbkontroll vars NavigateUrl egenskap är bunden till BrochurePath värdet. Ersätt den här markeringen med ett anrop till metoden GenerateBrochureLinkoch skicka in värdet BrochurePathför :

<asp:TemplateField HeaderText="Brochure">
    <ItemTemplate>
        <%# GenerateBrochureLink(Eval("BrochurePath")) %>
    </ItemTemplate>
</asp:TemplateField>

Skapa sedan en protected metod i den ASP.NET sidans kod bakom-klass med namnet GenerateBrochureLink som returnerar en string och accepterar en object som indataparameter.

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()));
}

Den här metoden avgör om det inskickade object värdet är en databas NULL och i så fall returnerar ett meddelande som anger att kategorin saknar en broschyr. Annars visas det i en hyperlänk om det finns ett BrochurePath värde. Observera att om värdet BrochurePath finns skickas det till ResolveUrl(url) metoden. Den här metoden löser den införda URL:en och ersätter ~ tecknet med lämplig virtuell sökväg. Om programmet till exempel är rotat vid /Tutorial55, kommer ResolveUrl("~/Brochures/Meats.pdf") att returnera /Tutorial55/Brochures/Meat.pdf.

Bild 10 visar sidan efter att ändringarna har tillämpats. Observera att fältet Fisk- och skaldjurskategori BrochurePath nu visar texten Ingen broschyr tillgänglig .

Texten 'Ingen broschyr tillgänglig' visas för de kategorier som saknar broschyr

Bild 10: Texten Ingen tillgänglig broschyr visas för de kategorier som saknar broschyr (Klicka för att se bilden i full storlek)

Steg 3: Lägga till en webbsida för att visa en kategoribild

När en användare besöker en ASP.NET-sida får de HTML-koden för ASP.NET sidan. Den mottagna HTML-koden är bara text och innehåller inga binära data. Ytterligare binära data, till exempel bilder, ljudfiler, Macromedia Flash-program, inbäddade Windows Media Player-videor och så vidare, finns som separata resurser på webbservern. HTML-koden innehåller referenser till dessa filer, men innehåller inte det faktiska innehållet i filerna.

I HTML används elementet <img> till exempel för att referera till en bild, med src attributet som pekar på bildfilen så här:

<img src="MyPicture.jpg" ... />

När en webbläsare tar emot den här HTML-koden skickar den en annan begäran till webbservern om att hämta det binära innehållet i bildfilen, som sedan visas i webbläsaren. Samma begrepp gäller för binära data. I steg 2 skickades broschyren inte ned till webbläsaren som en del av sidans HTML-kod. I stället tillhandahöll den renderade HTML-koden hyperlänkar som, när de klickades, fick webbläsaren att begära PDF-dokumentet direkt.

För att visa eller tillåta användare att ladda ned binära data som finns i databasen måste vi skapa en separat webbsida som returnerar data. För vårt program finns det bara ett binärt datafält som lagras direkt i databasen som kategorins bild. Därför behöver vi en sida som när den anropas returnerar bilddata för en viss kategori.

Lägg till en ny ASP.NET sida i BinaryData mappen med namnet DisplayCategoryPicture.aspx. När du gör det lämnar du kryssrutan Välj huvudsida avmarkerad. Den här sidan förväntar sig ett CategoryID värde i frågesträngen och returnerar binära data för kolumnen kategori s Picture . Eftersom den här sidan returnerar binära data och inget annat behöver den ingen markering i HTML-avsnittet. Klicka därför på fliken Källa i det nedre vänstra hörnet och ta bort alla sidmarkeringar förutom <%@ Page %> direktivet. Det innebär att DisplayCategoryPicture.aspx deklarativ markering ska bestå av en enda rad:

<%@ Page Language="C#" AutoEventWireup="true" 
    CodeFile="DisplayCategoryPicture.aspx.cs" 
    Inherits="BinaryData_DisplayCategoryPicture" %>

Om du ser MasterPageFile attributet i <%@ Page %> direktivet tar du bort det.

Lägg till följande kod i Page_Load-händelsehanteraren på sidans code-behind-klass:

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);
}

Den här koden börjar med att läsa in CategoryID värdet querystring i en variabel med namnet categoryID. Därefter hämtas bilddata via ett anrop till CategoriesBLL metoden class s GetCategoryWithBinaryDataByCategoryID(categoryID) . Denna data returneras till klienten genom Response.BinaryWrite(data) metoden, men innan detta sker måste Picture kolumnens värdes OLE-huvud tas bort. Detta uppnås genom att skapa en byte matris med namnet strippedImageData som innehåller exakt 78 tecken mindre än vad som finns i Picture kolumnen. MetodenArray.Copy används för att kopiera data från category.Picture med start vid position 78 över till strippedImageData.

Egenskapen Response.ContentType anger MIME-typen av innehåll som returneras så att webbläsaren vet hur det ska återges. Categories Eftersom tabellens kolumn är en bitmappsbild används bitmappens Picture MIME-typ här (bild/bmp). Om du utelämnar MIME-typen visar de flesta webbläsare fortfarande bilden korrekt eftersom de kan härleda typen baserat på innehållet i bildfilens binära data. Det är dock klokt att inkludera MIME-typen när det är möjligt. Se Internet Assigned Numbers Authority:s webbplats för en fullständig lista över MIME-medietyper.

När den här sidan har skapats kan en viss kategoris bild visas genom att besöka DisplayCategoryPicture.aspx?CategoryID=categoryID. Bild 11 visar bilden för kategorin Drycker, som kan visas från DisplayCategoryPicture.aspx?CategoryID=1.

Dryckkategorins bild visas

Bild 11: Dryckkategorins bild visas (Klicka om du vill visa en bild i full storlek)

Om du vid ett besök på DisplayCategoryPicture.aspx?CategoryID=categoryID får ett undantagsmeddelande som lyder Det går inte att omvandla objekt av typen 'System.DBNull' till typen 'System.Byte[]', kan det bero på två saker. Först tillåter Categories kolumnen i Picture tabellen NULL värden. Sidan DisplayCategoryPicture.aspx, däremot, förutsätter att det finns ett värde som inte är NULL närvarande. Egenskapen Picture för den CategoriesDataTable kan inte nås direkt om den har ett NULL värde. Om du vill tillåta NULL värden för Picture kolumnen vill du inkludera följande villkor:

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 ...
}

Koden ovan förutsätter att det finns en bildfil med namnet NoPictureAvailable.gif i mappen Images som du vill visa för dessa kategorier utan bild.

Det här undantaget kan också orsakas om CategoriesTableAdapter s-metodens GetCategoryWithBinaryDataByCategoryIDSELECT -instruktionen har återställts till huvudfrågans kolumnlista, vilket kan inträffa om du använder ad hoc SQL-instruktioner och du har kört guiden igen för TableAdapter-huvudfrågan. Kontrollera att GetCategoryWithBinaryDataByCategoryID metodens SELECT -instruktion fortfarande innehåller Picture kolumnen.

Anmärkning

Varje gång DisplayCategoryPicture.aspx besöks, görs en åtkomst till databasen och bilddata för den angivna kategorin returneras. Om kategorins bild inte har ändrats eftersom användaren senast har visat den är det dock slöseri med arbete. Lyckligtvis tillåter HTTP villkorsstyrda GET:er. Med en villkorsstyrd GET skickar klienten som gör HTTP-begäran tillsammans med ett If-Modified-Since HTTP-huvud som anger datum och tid då klienten senast hämtade den här resursen från webbservern. Om innehållet inte har ändrats sedan det här angivna datumet kan webbservern svara med statuskoden Inte ändrad (304) och avstå från att skicka tillbaka den begärda resursens innehåll. Den här tekniken gör att webbservern inte behöver skicka tillbaka innehåll för en resurs om den inte har ändrats sedan klienten senast kom åt den.

För att implementera det här beteendet måste du dock lägga till en PictureLastModified kolumn i Categories tabellen för att registrera när Picture kolumnen senast uppdaterades samt kod för att kontrollera If-Modified-Since rubriken. Mer information om If-Modified-Since-huvudet och det villkorsstyrda GET-arbetsflödet finns i HTTP Conditional GET for RSS Hackers och A Deeper Look at Performing HTTP Requests in an ASP.NET Page.

Steg 4: Visa kategoribilderna i en GridView

Nu när vi har en webbsida för att visa en viss kategoribild kan vi visa den med hjälp av bildwebbkontrollen eller ett HTML-element <img> som pekar på DisplayCategoryPicture.aspx?CategoryID=categoryID. Bilder vars URL bestäms av databasdata kan visas i GridView eller DetailsView med hjälp av ImageField. ImageField innehåller DataImageUrlField och DataImageUrlFormatString egenskaper som fungerar som HyperLinkField s DataNavigateUrlFields och DataNavigateUrlFormatString egenskaper.

Låt oss förbättra Categories GridView i DisplayOrDownloadData.aspx genom att lägga till ett ImageField för att visa varje kategoris bild. Lägg bara till ImageField och ange dess egenskaper DataImageUrlField och DataImageUrlFormatString till CategoryID och DisplayCategoryPicture.aspx?CategoryID={0} respektive. Då skapas en GridView-kolumn som renderar ett <img> element vars src attribut refererar till DisplayCategoryPicture.aspx?CategoryID={0}, där {0} ersätts med gridview-radens CategoryID värde.

Lägga till ett ImageField i GridView

Bild 12: Lägg till ett ImageField i GridView

När du har lagt till ImageField bör gridViews deklarativa syntax se ut så här:

<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>

Ta en stund och titta på den här sidan via en webbläsare. Observera hur varje postering nu innehåller en bild för kategorin.

Kategorins bild visas för varje rad

Bild 13: Kategorins bild visas för varje rad (klicka om du vill visa en bild i full storlek)

Sammanfattning

I den här handledningen undersökte vi hur man presenterar binära data. Hur data presenteras beror på typen av data. För PDF-broschyrfilerna erbjöd vi användaren en vybroschyrlänk som när den klickades tog användaren direkt till PDF-filen. För kategorins bild skapade vi först en sida för att hämta och returnera binära data från databasen och använde sedan den sidan för att visa varje kategoribild i en GridView.

Nu när vi har tittat på hur du visar binära data är vi redo att undersöka hur du utför infogning, uppdateringar och borttagningar mot databasen med binära data. I nästa självstudie tittar vi på hur du associerar en uppladdad fil med motsvarande databaspost. I självstudien efter det får vi se hur du uppdaterar befintliga binära data samt hur du tar bort binära data när dess associerade post tas bort.

Lycka till med programmerandet!

Om författaren

Scott Mitchell, författare till sju ASP/ASP.NET-böcker och grundare av 4GuysFromRolla.com, har arbetat med Microsofts webbtekniker sedan 1998. Scott arbetar som oberoende konsult, tränare och författare. Hans senaste bok är Sams Teach Yourself ASP.NET 2.0 på 24 timmar. Han kan nås på mitchell@4GuysFromRolla.com.

Särskilt tack till

Den här självstudieserien granskades av många användbara granskare. Huvudgranskare för den här självstudien var Teresa Murphy och Dave Gardner. Vill du granska mina kommande MSDN-artiklar? Om så är fallet, hör av dig på mitchell@4GuysFromRolla.com.