首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> ASP.NET 基礎 >> 關於ASP.NET

ASP.NET 2.0 資料教程:在 Data Web 控制項顯示二進位資料 (GridView/DetailsView 圖片與下載連結)

     編輯:關於ASP.NET

二進位資料呈現方式取決於類型:圖片渲染為 <img>,文件提供下載連結。本文示範在 GridView 與 DetailsView 中顯示 Northwind Categories 表的 Picture (位圖含 OLE 報頭) 與 BrochurePath (PDF 路徑)。

資料準備:手動填入 BrochurePath

因尚未建立上傳介面,先在資料庫手動設定 7 類別的 PDF 路徑 (Seafood 留空測試無檔案情況):

UPDATE Categories SET BrochurePath = '~/Brochures/Beverages.pdf' WHERE CategoryID = 1;
UPDATE Categories SET BrochurePath = '~/Brochures/Condiments.pdf' WHERE CategoryID = 2;
-- ... 其他類別
UPDATE Categories SET BrochurePath = NULL WHERE CategoryName = 'Seafood';

手工為 BrochurePath 賦值

核心挑戰:Picture 欄位含 78 位元組 OLE 報頭

Northwind 來源為 Access,Picture 為 OLE 物件欄位,前 78 位元組為報頭,直接輸出無法顯示。需移除報頭後輸出純位圖資料。

建立圖片輸出頁面:GetImage.aspx

<%@ Page Language="C#" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<%@ Import Namespace="System.Configuration" %>
<script runat="server">
    protected void Page_Load(object sender, EventArgs e)
    {
        string catId = Request.QueryString["CategoryID"];
        if (string.IsNullOrEmpty(catId)) return;

        string connStr = ConfigurationManager.ConnectionStrings["NorthwindConnectionString"].ConnectionString;
        using (SqlConnection conn = new SqlConnection(connStr))
        using (SqlCommand cmd = new SqlCommand("SELECT Picture FROM Categories WHERE CategoryID = @CategoryID", conn))
        {
            cmd.Parameters.AddWithValue("@CategoryID", catId);
            conn.Open();
            object result = cmd.ExecuteScalar();
            
            if (result != null && result != DBNull.Value)
            {
                byte[] oleData = (byte[])result;
                // 移除前 78 位元組 OLE 報頭
                const int OleHeaderSize = 78;
                if (oleData.Length > OleHeaderSize)
                {
                    byte[] imageData = new byte[oleData.Length - OleHeaderSize];
                    Buffer.BlockCopy(oleData, OleHeaderSize, imageData, 0, imageData.Length);
                    
                    Response.ContentType = "image/bmp"; // 原為 16 色 BMP
                    Response.BinaryWrite(imageData);
                }
            }
        }
    }
</script>

GridView 顯示圖片與下載連結

<asp:GridView ID="gvCategories" runat="server" 
    DataSourceID="odsCategories" 
    AutoGenerateColumns="False"
    DataKeyNames="CategoryID">

    <Columns>
        <asp:BoundField DataField="CategoryID" HeaderText="ID" />
        <asp:BoundField DataField="CategoryName" HeaderText="類別名稱" />
        <asp:BoundField DataField="Description" HeaderText="描述" />
        
        <asp:TemplateField HeaderText="圖片">
            <ItemTemplate>
                <asp:Image ID="imgPic" runat="server" 
                    ImageUrl='<%# "GetImage.aspx?CategoryID=" + Eval("CategoryID") %>' 
                    AlternateText='<%# Eval("CategoryName") %>'
                    Height="80px" />
            </ItemTemplate>
        </asp:TemplateField>
        
        <asp:TemplateField HeaderText="小冊子">
            <ItemTemplate>
                <%# !String.IsNullOrEmpty(Convert.ToString(Eval("BrochurePath"))) ? 
                    $"<a href='{Eval("BrochurePath")}' target='_blank' class='download-link'><i class='icon-pdf'></i> 下載 PDF</a>" : 
                    "無" %>
            </ItemTemplate>
        </asp:TemplateField>
    </Columns>
</asp:GridView>

<asp:ObjectDataSource ID="odsCategories" runat="server" 
    TypeName="BLL.CategoriesBLL" 
    SelectMethod="GetCategories" />

DetailsView 詳細檢視

<asp:DetailsView ID="dvCategory" runat="server" 
    DataSourceID="odsCategories" 
    AutoGenerateRows="False"
    DataKeyNames="CategoryID">

    <Fields>
        <asp:BoundField DataField="CategoryID" HeaderText="ID" ReadOnly="True" />
        <asp:BoundField DataField="CategoryName" HeaderText="類別名稱" />
        <asp:BoundField DataField="Description" HeaderText="描述" HtmlEncode="False" />
        
        <asp:TemplateField HeaderText="圖片">
            <ItemTemplate>
                <asp:Image ID="imgDetail" runat="server" 
                    ImageUrl='<%# "GetImage.aspx?CategoryID=" + Eval("CategoryID") %>' 
                    AlternateText='<%# Eval("CategoryName") %>' />
            </ItemTemplate>
        </asp:TemplateField>
        
        <asp:TemplateField HeaderText="小冊子">
            <ItemTemplate>
                <asp:HyperLink ID="hlBrochure" runat="server" 
                    NavigateUrl='<%# Eval("BrochurePath") %>' 
                    Text="下載小冊子 (PDF)" 
                    Target="_blank"
                    Visible='<%# !String.IsNullOrEmpty(Convert.ToString(Eval("BrochurePath"))) %>' />
            </ItemTemplate>
        </asp:TemplateField>
    </Fields>
</asp:DetailsView>

進階:通用二進位輸出 HttpHandler (取代 .aspx)

// BinaryHandler.ashx
public class BinaryHandler : IHttpHandler
{
    public void ProcessRequest(HttpContext context)
    {
        string type = context.Request.QueryString["type"]; // "image" or "brochure"
        string id = context.Request.QueryString["id"];
        
        if (string.IsNullOrEmpty(id)) return;

        // 從 DAL/BLL 取得 byte[] 或檔案路徑
        byte[] data = GetBinaryData(type, id);
        string contentType = type == "image" ? "image/bmp" : "application/pdf";
        string fileName = type == "image" ? $"cat_{id}.bmp" : $"brochure_{id}.pdf";

        context.Response.Clear();
        context.Response.ContentType = contentType;
        context.Response.AddHeader("Content-Disposition", $"inline; filename=\"{fileName}\"");
        context.Response.BinaryWrite(data);
        context.Response.End();
    }

    private byte[] GetBinaryData(string type, string id)
    {
        // 實作從資料庫/檔案系統讀取
        return new byte[0];
    }

    public bool IsReusable => false;
}

Web.config 註冊:<add name="BinaryHandler" verb="*" path="BinaryHandler.ashx" type="Namespace.BinaryHandler" />

效能優化建議

問題方案
每次請求查詢資料庫圖片輸出 HTTP 快取標頭:Response.Cache.SetCacheability(HttpCacheability.Public); Response.Cache.SetMaxAge(TimeSpan.FromDays(30));
大量圖片併發將圖片轉為實體檔案儲存於磁碟/CDN,資料庫僅存路徑
OLE 報頭每次移除資料遷移時一次性轉檔為標準 BMP/JPG,更新資料庫
PDF 下載大檔案使用 Response.TransmitFile (傳送檔案不載入記憶體) 或 FileResult (MVC/Core)

結語

顯示二進位資料的關鍵在於:圖片需專用輸出端點移除 OLE 報頭、文件提供下載連結而非內嵌、善用 HTTP 快取減輕資料庫壓力。現代架構建議將二進位檔案移出資料庫,改用物件儲存 (Blob Storage) + CDN,資料庫僅存 URL 與中繼資料。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved