目前为止,本章示例关注的重点在于获取来自数据库的文本、数字和日期信息。然而,数据库还经常存储一些其他的二进制数据,例如图片。假设 Product表使用二进制字段保存了每个产品的图片。在ASP.NET Web页面中获取该数据很容易,但是显示它却不简单。主要问题是为了在HTML页面中显示数据,需要添加图片标记,利用src属性连接独立的图片文件。例 如,
<%@ Page Language="C#" %> |
不幸的是,如果动态显示图片数据,就不能使用这种方法。虽然可以在代码中设置src属性,但是无法以编程方式设置图片内容。可以首先在Web服务器 的硬盘上,将数据存储为图片文件,但是这种方法明显很慢,浪费空间,如果在同一时间受理了多个请求,则可能引起并发错误,它们可能会试图写同一个文件。
解决这个问题有两种方法。一种方法是将所有图片都存储为独立文件,数据库记录只需简单的存储文件名称,接着将文件名绑定到服务器端图片上。这是一种 很合理的解决方案,但是这种方法在某些情况下却无能为力。例如将图片存储于数据库中,以便利用RDBMS的缓存数据、记录日志和备份功能时。
规则提示,只要图片不是很大(例如,不超过50M),同时不需要利用其他应用程序频繁编辑图片,就可以将图片存储在数据库中。
在这些情况下,解决方案使用可直接返回二进制数据的ASP.NET方法。然后,在Web页面的控件中就可以使用这些二进制数据。为了完成这个任务, 需要实现数据绑定和编写自定义ADO.NET代码。对于本示例,获取AdventureWorks数据库的Product表中存储的每个产品的图片,接着 随同产品详情显示这些图片。这些图片存储在ProductPhoto表中,同时使用另一个ProductProductPhoto表链接Product和 ProductPhoto表。在本示例中使用的ASP.NET页面将在获取产品细节的同时获取产品图片,同时使用GridView控件显示这些信息。以下 是实现这个功能所需的步骤:
① 创建执行获取图片的HttpHandler。
② 在Web.config文件中注册HttpHandler。
③ 使用HttpHandler在GridView中显示图片。
以下章节将详细讲解每个步骤。
1.创建HttpHandler
ASP.NET提供了一个低级别的请求/响应API,以HTTP处理程序格式组织,用于自定义方式处理和维护输入HTTP请求。为了实现这一功能,可编写一个实现System.Web.IHttpHandler接口的类,同时实现IHttpHandler接口的方法。
对于处理HTTP请求,当使用高级页面框架抽象来提供服务不是很有效时,使用处理程序却往往能发挥作用。处理程序通常用于过滤器和类似的CGI应用 程序,尤其是可用于返回二进制数据。ASP.NET收到的每个输入HTTP请求最终都是由一个特定的实现IHttpHandler接口的类实例来处理。
如 前文所述,所有HttpHandler必须实现IHttpHandler接口。某些内置的类(例如HttpApplication)和Page类都已经实 现了IHttpHandler接口。IHttpHandler接口很简单。该接口包括只读属性IsReusable,该属性返回Boolean值(通常为 true),用于指示是否另一个请求能够使用IHttphandler实例。同时,该接口还包括ProcessRequest()方法,该方法包含 HttpContext类型的参数,用于执行处理扩展的工作。
bool IsReusable {get;} |
通过提供给ProcessRequest()方法的HttpContext对象,能够获取针对Request和Response对象的引用。
既然读者已经了解了HttpHandler的基本知识,那么就可以创建一个名为ImageHandler的HttpHandler类(表示为 ImageHandler.ashx),该处理程序能够获取ProductPhoto表中的图片。示例10-4列举了ImageHandler的实现代 码。
示例10-4:获取图片的HttpHandler
using System; public class ImageHandler : IHttpHandler |
ProcessRequest()方法是类代码的主体。该方法首先从查询字符串中获取PhotoID。然后使用该值在ProductPhoto表中执行SQL查询,该查询根据图片ID返回ThumbNailPhoto列值。
当开始处理查询结果时,会逐段读取ProductPhoto表的ThumbNailPhoto列,接着使用 Response.BinaryWrite()方法将数据以块方式写入输出流中。为了实现这一点,可指示SqlDataReader对象使用它所支持的顺 序访问功能。为了使用顺序访问功能,需要向SqlCommand.ExecuteReader()方法提供Command对象的 CommandBehavior. SequentialAccess值。然后,使用SqlDataReader.GetBytes()方法每次整体移动一行。
当使用顺序访问时,要记住一些限制。首先,必须将数据作为只向前的流进行读取。一旦读取了一块数据,会自动移向流中的前面数据,并且不能后退。其 次,必须使用与查询返回的字段的相同顺序来读取字段。例如,如果查询返回3个列,第三个列是二进制字段,那么必须在访问第三个字段的二进制数据之前,返回 第一个和第二个字段的值。如果首先访问第三个字段,则不能访问前两个字段。
GetBytes()方法返回获取的字节数的值。如果需要确定字段的总字节数,只需在调用GetBytes()方法时传递空引用,而不是缓冲区。
2.注册处理程序
既然已经创建了处理程序,下一步是在Web.config文件中注册处理程序。在这之前,需要将编译后的程序集(包括 ImageHandler类)置于Web站点根目录下的bin文件夹中。在将程序集存储到bin文件夹中之后,可根据如下方式在Web.config文件 的<httpHandlers>节中注册处理程序:
<system.web> |
以上用于在Web.config文件中注册程序集。使用以上注册,所有针对ImageHandler.ashx的HTTP GET请求都将由ImageHandler类实例处理。
3.使用HttpHandler
既然已经创建和注册了HttpHandler,那么应该在ASP.NET页面中使用它,以便显示图片。示例10-5列举了ASP.NET页面代码。
示例10-5:使用ASP.NET页面的ImageHandler
<%@ Page Language="C#" %> |
<img src='ImageHandler.ashx?PhotoID=<%# Eval("ProductPhotoID")%>'/> |
![]() |
图10-5 |