欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

在ASP.NET 2.0中操作数据之五十三:在Data Web控件显示二进制数据

程序员文章站 2024-02-11 20:38:40
导言:   在前面的教程我们阐述了应用程序处理二进制数据的2种模式,以及使用fileupload 控件从浏览器向服务器文件系统上传文件。当文件上传并存储在文件系统里时,应...

导言:

  在前面的教程我们阐述了应用程序处理二进制数据的2种模式,以及使用fileupload 控件从浏览器向服务器文件系统上传文件。当文件上传并存储在文件系统里时,应在相应的数据库记录里存储该文件的存储路径。

  我们先来看如何为最终用户提供二进制数据。怎样展示二进制数据呢?这取决于其类型。比如图片,我们将其显示为image;如果是pdfs,microsoft word文档、zip文件或其它类型的数据,或许提供一个“download”链接比较妥当。

  在本节,我们看如何在gridview和detailsview一类的数据web控件里呈现二进制数据,在后面的教程我们将注意力转向将上传文件和数据库联系起来。

第一步:提供brochurepath值

  表categories的picture列存储相关类的图片信息。具体的讲,为16色的低质量位图,大小为172乘120像素,约11 kb。另外还包括一个约78字节的ole报头,在显示图片的时候需要将其剥离。为什么会有报头信息呢?因为数据库northwind源于微软的access数据库。在access里二进制数据ole类型来存储的,该类型会添加报头。现在,我们看如何从图片剥离报头,以便显示。在后面的教程我们将创建一个界面,将带报头的这些位图替换为不带报头的等价的jpg图片。

  前面我们考察了如何使用fileupload控件,让我们继续为服务器文件系统添加文件。不过暂时不用更新categories表的brochurepath列,那是下一章的内容。我们现在需要手工为brochurepath赋值。

  在本教程,当你下载东西时,可以看到在~/brochures7文件夹有7个pdf小册子,每个小册子对应一个种类,seafood除外。我故意没为seafood提供pdf小册子,以便探讨如何处理某些记录没有附带二进制数据的情况。在服务器资源管理器里右键点击categories,选“查看表数据”,输入文件路径,如图1所示。由于seafood类没有图片,将其brochurepath的值设为“null”。 

在ASP.NET 2.0中操作数据之五十三:在Data Web控件显示二进制数据
图1:手工为表categories的brochurepath列键入值

第2步:在gridview里添加一个下载链接

  当为表categories的brochurepath列赋值后,我们准备创建一个gridview用于展示每个种类,并附带一个链接下载每个类的小册子。在第4步我们将扩展gridview以显示每个类的图片。

  打开binarydata文件夹的displayordownloaddata.aspx页面并进入设计模式,从工具箱里拖一个gridview控件到页面,设其id为categories,从其智能标签选择绑定到一个名为categoriesdatasource的objectdatasource控件。该控件调用类categoriesbll的getcategories()方法。

在ASP.NET 2.0中操作数据之五十三:在Data Web控件显示二进制数据
图2:创建一个名为categoriesdatasource的objectdatasource控件

在ASP.NET 2.0中操作数据之五十三:在Data Web控件显示二进制数据
图3:设置objectdatasource使用categoriesbll类

在ASP.NET 2.0中操作数据之五十三:在Data Web控件显示二进制数据
图4:调用getcategories()方法

  完成设置后,visual studio自动的为categoryid, categoryname, description, numberofproducts和brochurepath生成boundfield。移除numberofproducts,因为getcategories()方法用不上,同样将categoryid移除了。分别把categoryname和 brochurepath的headertext属性改为“category”和“brochure”。做上述修改后,你的gridview and objectdatasource的声明代码看起来应该像下面的这样:

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

  在浏览器查看该页(如图5)。列出了所有的8个类,除了seafood,其它7个类的boundfield列里显示各自的brochurepath值。由于seafood的brochurepath为null值,看起来为空格。

在ASP.NET 2.0中操作数据之五十三:在Data Web控件显示二进制数据
图5:显示了每个类别的name, description和brochurepath值

  与其显示brochurepath的text值,不如创建一个指向小册子的链接。移除brochurepath,代之以hyperlinkfield。设它的headertext属性为“brochure”,text属性为“view brochure”, datanavigateurlfields属性为“ brochurepath”。

 

在ASP.NET 2.0中操作数据之五十三:在Data Web控件显示二进制数据
图6:添加一个指向brochurepath的hyperlinkfield

  这样将在gridview里添加一列链接,如图7所示。点“view brochure”时要么直接在浏览器显示pdf,要么提示用户下载该文件。这取决于浏览器的设置以及是否安装了pdf阅读器。

在ASP.NET 2.0中操作数据之五十三:在Data Web控件显示二进制数据
图7:点击“view brochure”访问某类的brochure

在ASP.NET 2.0中操作数据之五十三:在Data Web控件显示二进制数据
图8:显示某类的pdf文件

隐藏无小册子图片的类的“view brochure” 文本

  如图7所示,不管某个类的brochurepath是否为null值,名为brochurepath的hyperlinkfield都呈现为其text属性(“view brochure”) 。当然,如果brochurepath为null值,链接只显示为文本(而不带下划线),就像seafood类一样(见图7)。与显示文本“view brochure”相比,更为可取的是将那些brochurepath值为空的类显示为“no brochure available”。

  为达此目的,我们需要用到templatefield,使其产生一个基于brochurepath值的合适的结果。我们先来看看如何实现,就像在教程之12《在gridview控件中使用templatefield》一样。

  在“编辑列”对话框里选中名为brochurepath的hyperlinkfield,再点“convert this field into a templatefield”链接,将其转换为templatefield。 

在ASP.NET 2.0中操作数据之五十三:在Data Web控件显示二进制数据
图9:将hyperlinkfield转换为templatefield

  这样将创建一个templatefield,其itemtemplate模板包含一个hyperlink web控件,该控件的navigateurl属性为brochurepath值。用下面的代码将其替换掉:

<asp:templatefield headertext="brochure">
 <itemtemplate>
 <%# generatebrochurelink(eval("brochurepath")) %>
 </itemtemplate>
</asp:templatefield>

  然后,在asp.net页面的“后台代码”里添加一个protected类型的generatebrochurelink方法,它接受一个输入参数并返回一个字符串。

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

  该方法判断传入的值是否为null。如果是,则返回一个消息指出该类没有小册子文件;相反,如果传入值不为空,将显示为一个链接。我们注意到,当brochurepath值不为空时,将调用resolveurl(url)方法。该方法的作用在于将传入的相对路径转换为物理路径。比如应用程序的根目录在/tutorial55,resolveurl("~/brochures/meats.pdf")返回的路径是/tutorial55/brochures/meat.pdf.

图10为经过上述修改后的界面。我们注意到seafood类的brochurepath列现在显示为文本“no brochure available”.

在ASP.NET 2.0中操作数据之五十三:在Data Web控件显示二进制数据
图10:没有小册子的类将显示为文本“no brochure available”

第3步:新增页面以显示类的图片

  当用户访问一个asp.net页面时,他将接收该页面的html代码。html代码仅仅包含了text文本,而并不包含任何的二进制数据。任何的二进制数据,比如图片,音乐文件、flash程序、windows media player视频等,以独立资源的形式存放于服务器。

  html只包含了这些文件的引用,并不包含这些文件本身。

  比如,在html里<img>元素用来引用一张图片,其src属性指向该图片文件,如:
<img src="mypicture.jpg" ... />

  当浏览器收到html代码时,它向服务器发送获取图片的请求并将其显示在浏览器中,该模式对所有的二进制数据都适用。在第2步中,我们没有在页面的html标记里将小册子显示在浏览器,而是在html标记里提供一个超链接,当点击它是,导致浏览器直接请求pdf文件。

  为了显示或允许用户下载储存在数据库中的二进制数据,我们需要另外创建一个页面,用于从数据库返回所需的数据。对我们的应用程序而言,由于直接存储在数据库中的二进制数据只有一项——类的图片,所以我们需要一个页面,当需要时从数据库返回某个特定类的图片。

  在binarydata文件夹添加一个displaycategorypicture.aspx页面,注意不要使用母版页。该页面接受一个包含categoryid值的查询字符串,返回picture列的二进制数据。由于该页只返回二进制数据,所以我们不需要页面的html部分有任何代码。进入页面的“源码”模式,删除页面的所有代码,只保留<%@ page %>部分。也即:displaycategorypicture.aspx页面的声明代码应该只由如下的单独行构成:

<%@ page language="c#" autoeventwireup="true"
 codefile="displaycategorypicture.aspx.cs"
 inherits="binarydata_displaycategorypicture" %>

如果<%@ page %>里包含有masterpagefile属性,将其删除,同时在后台代码类的page_load事件处理器里添加如下代码:

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

  代码先读取查询字符串的categoryid值,并对名为categoryid的变量赋值。然后,通过调用categoriesbll类的
getcategorywithbinarydatabycategoryid(categoryid)方法获取图片数据,再通过response.binarywrite(data)方法向客户端返回数据。不过在此之前先要剥离数据的ole报头。怎么实现呢?创建一个名为strippedimagedata的byte数组,它包含的字节刚好比picture列的数据少78。而array.copy方法将从category.picture的第78个字节开始复制数据(即刚好剥离ole报头)。

  代码中的response.contenttype属性指定了要返回内容的mime type,以便浏览器知道如何显示数据。由于categories表的picture列存储的是位图图片,故在这里,位图图片的mime type是(image/bmp). 如果你忽视了mime type,绝大多数浏览器也可以正确的显示图像,因为,它们能根据图像文件的二进制数据的内容而推断其类型。即便如此,还是尽可能的使用mime type。

创建页面后,可以访问页面

displaycategorypicture.aspx?categoryid=categoryid来查看某个特定类的图片。图11显示的是beverages类的图片,页面为
displaycategorypicture.aspx?categoryid=1.

在ASP.NET 2.0中操作数据之五十三:在Data Web控件显示二进制数据
图11:显示类beverages的图片

  有时候,当你访问displaycategorypicture.aspx?categoryid=categoryid页面时,有可能显示这样的提示:“unable to cast object of type 'system.dbnull' to type 'system.byte[]'”。原因有可能是如下2方面。第一,表categories的picture列允许为null值,而displaycategorypicture.aspx page页面总是假定传入的为非null值。当picture为null值时,不能直接访问categoriesdatatable的picture属性。如果你允许picture为null值,添加如下代码:

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

  上述代码假定在images文件夹里存在名为nopictureavailable.gif的图片,当某个类没有图片时,就显示该图片。

  另一种情况:当你在向导里选用“使用sql语句”的模式再次运行主查询时,它将影响getcategorywithbinarydatabycategoryid方法的select命令返回的列(换句话说,主查询没有返回picture列,再次运行主查询时将使getcategorywithbinarydatabycategoryid方法也不会返回picture列)。所以,应确保getcategorywithbinarydatabycategoryid方法的select命令返回picture列。

  注意:每次访问displaycategorypicture.aspx页面时,都会访问数据库并返回所需的图片。如果图片自最近一次访问以来没有改变过的话,这样每次访问数据库再返回数据的做法效率是不高的。幸运的是,http允许使用conditional gets,这样的话,客户端使http请求发送一个if-modified-since http header。if-modified-since http header包含了客户端最近一次从服务器获取的数据以及时间。如果请求的内容没有发生改变,服务器响应为not modified status code (304),并不返回请求的内容。简而言之,如果请求的资源自最近一次访问以来没发送改变的话,服务器将不会回传该资源,以达到减轻服务器负荷的目的。

第四步:在gridview控件里显示category pictures

  现在我们有一个web页面来显示某个特定种类的图片的。通过image web控件或 html <img>元素来指向displaycategorypicture.aspx?categoryid=categoryid页面,从而达到显示该图片的目的。我们可以在gridview控件或detailsview控件的 imagefield里显示图片。imagefield的dataimageurlfield属性、dataimageurlformatstring属性与hyperlinkfield的datanavigateurlfields属性、datanavigateurlformatstring属性用法相似。

  让我们对displayordownloaddata.aspx页面里名为categories的gridview控件进行扩充。添加一个imagefield,设其dataimageurlfield属性为categoryid;
dataimageurlformatstring属性为displaycategorypicture.aspx?categoryid={0}。这样将为gridview增加一列,呈现为一个<img>元素,其src属性为displaycategorypicture.aspx?categoryid={0},其中{0}将由gridview row的categoryid值填充。

在ASP.NET 2.0中操作数据之五十三:在Data Web控件显示二进制数据
图12:为gridview控件添加一个imagefield

添加完成后,你的gridview控件的声明代码看起来应像下面这样:

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

花几分钟在浏览器里查看该页面,注意每一行记录现在都包含一张该类的图片。

在ASP.NET 2.0中操作数据之五十三:在Data Web控件显示二进制数据
图13:每一行记录都显示一张图片

总结:

  在本节我们探讨了如何显示二进制数据,数据是如何呈现的取决于它的类型。对pdf小册子文件来说,我们提供了一个“view brochure”链接,当点击它时,直接将用户指向pdf小册子文件。对某个种类的图片,我们先是创建一个页面来从数据库获取并显示它,然后再在一个gridview控件里显示图片。既然看到了如何展示二进制数据,我们准备探讨如何对其展开插入、更新、删除操作。接下来的教程我们看如何将上传文件和相应的数据库记录联系起来。然后,再探讨如何更新现存的二进制数据,以及当删除数据库记录时如何删除相应的二进制数据。

  祝编程快乐!

作者简介

  本系列教程作者 scott mitchell,著有六本asp/asp.net方面的书,是4guysfromrolla.com的创始人,自1998年以来一直应用 微软web技术。大家可以点击查看全部教程《[翻译]scott mitchell 的asp.net 2.0数据教程》,希望对大家的学习asp.net有所帮助。

相关标签: ASP.NET 二进制