二、 动态图像生成问题
至此,我们已经分析了AdRotator类直接使用指向图像文件的URL,而不是字节流或二进制数组数据或任何其它可能描述一个图像的形式。当该图像以二进制数据形式存储在一个数据库文件中时,这就提出了一个问题。一般地,你是不想把它们写向磁盘的,因为它们将再次占用很多的空间并且需要与数据库版本保持同步。幸运的是,在Visual Studio 2005中,这一切变得相当容易。
从根本上看,我们需要创建一个HTTP处理器类,它将拦截到一个特定的URL的调用并且以一种浏览器期望的格式返回该图像。有关IHTTPHandler接口,在此不再赘述,请参考MSDN文档。HTTP处理器给你提供一种与低级请求和IIS Web服务器的响应服务交互的方式,并且提供一种很类似于ISAPI扩展的功能,只是使用一种更为简单的编程模型。
下面是其中一个处理器类(ProductThumbNail.ashx)相应的代码。其它的与此基本一致,除了使用一个不同的TableAdaptor来检索较大的图像外。
在IHTTPHandler接口中实现的重要方法是ProcessRequest()。它能使你以低级方式存取上下文对象;该上下文对象又进一步存取Request和Response对象以便你能够得到作为一个查询字符串传递到URL中的ID(借助于Request),并且借助于Response对象返回内容。返回的内容仅仅是一个从表格中的二进制栏中获取的字节数组。注意,我仅取得在第一行的ThumbNailPhoto栏中的内容并且把它转换为一个字节数组。<%@ WebHandler Language="C#" Class="ProductThumbNail" %>
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Web;
using System.Web.Caching;
using System.Data;
using System.Data.Sql;
using System.Web.UI.WebControls;
using System.Web.Configuration;
using System.Configuration;
using System.Collections;
public class ProductThumbNail : IHttpHandler
...{
public void ProcessRequest (HttpContext context)...{
//从querystring中得到图像的ID,并且使用它生成一个缓存键。
String imageID = context.Request.QueryString["ID"];
String cacheKey = context.Request.CurrentExecutionFilePath + ":" + imageID;
Byte[] imageBytes;
//检查是否缓存中包含图像
Object cachedImageBytes = context.Cache.Get(cacheKey);
if (cachedImageBytes != null) ...{
imageBytes = (Byte[])cachedImageBytes;
}
else ...{
GetImageTableAdapters.ThumbNailTableAdapter oTA = new GetImageTableAdapters.ThumbNailTableAdapter();
GetImage.ThumbNailDataTable oDT = oTA.GetData(int.Parse(imageID));
if (oDT.Rows.Count == 0) ...{
//图像编号
//Photo ID为1显示“No Image Available”图像
oDT = oTA.GetData(1);
}
imageBytes = (byte[])oDT.Rows[0]["ThumbNailPhoto"];
//把它存储在缓存中(2个小时以后到期)
context.Cache.Add(cacheKey,imageBytes,null,
DateTime.MaxValue,new TimeSpan(2,0,0),
CacheItemPriority.Normal,null);
}
//回发图像
context.Response.ContentType = "image/jpeg";
context.Response.Cache.SetCacheability(HttpCacheability.Public);
context.Response.BufferOutput = false;
context.Response.OutputStream.Write(imageBytes,0,imageBytes.Length);
}
public bool IsReusable...{
get ...{return false;}
}
}
另外,为了往回发送图像,你只需要设置一下content type(注意,这可能来自于表格,或者由二进制形式的头部来动态决定),它负责告诉Response对象把数据“流回”,而不必等待数据流关闭,然后仅把字节数组写向输出流。
三、 小结
如今,大多数网站经常显示各式广告或邀请用户访问其他站点的类似动态内容。而ASP.NET 2.0中提供的AdRotator控件正可简化此任务。在当今IT广告世界里,这个小小的“精灵”控件将发挥越来越大的作用。