一、 AdRotator控件的三种数据源模式
AdRotator以三种不同的模式填充它的图像和导航属性,我把它们分别称为“数据库模式”,“XML模式”和“编程模式”。
(一) 数据库模式
在数据库模式下,一个AdRotator链接到一个数据源。该数据源表格至少需要三个数据列:一个相应于图像的URL,一个相应于该图像被点击时要导航到的URL,一个相应于要在该图像的ALT标签中被显示的字符串。下列是数据源表格中的可用字段,其中后面几个是可选的:
【注意】上表中提供的数据类型是SQL Server类型。如果使用的是不同的数据库,请替换相应的合适类型。
当然,借助于ASP.NET 2.0强大的数据源数据处理功能,你并不需要一个类似这样的数据表格,你只要在DataSource本身使用一个SQL语句把该数据“拖入”到适当的结构中。比如说,如果你是动态地显示SQL Server 2005 AdventureWorks示例数据库ProductPhoto表格中图像的缩略图,并且允许在点击一下这个缩略图后能够重定向到在同一个表格中的LargePhoto图像(也是动态生成的)并且使用该产品表格中的一个描述来表示相应的可选文本,那么你可以象下列这样来使用:
上面的代码将产生一个具有四栏的结果集。之后,AdRotator控件看起来如下所示:
这里的所有属性(除了DataSourceID及其名字外)都为其缺省值,因为我已经在DataSource的定义中使用缺省名来描述这些域。
(二) XML模式
另一种填充一个AdRotator的域的方式是使用一个静态XML文件,它有一个类似于表格模式的结构。本文下载源码中包含一个完整的示例。下面是一个简单摘要(一个称为Advertisments.xml的文件):
现在,该AdRotator看起来如下所示:
在此,我们也是使用了缺省值。
(三) 编程模式
无论AdRotator的AdCreated事件何时激发,都以编程方式填充该属性。此时,一个AdCreatedEventArgs对象被传递到事件处理器;而且你要设置三个属性:ImageURL,NavigateURL和AlternateText—它们都是用于生成控件之用的。
至此,该AdRotator控件看起来如下所示:
在code-behind文件中,我仅绑定了一个事件处理器:
这种情况可能非常有用。例如,你可以实现基于用户的导航历史,或基于他们已经实现的个性化或任何其它标准来实时的图像定位。
AdRotator以三种不同的模式填充它的图像和导航属性,我把它们分别称为“数据库模式”,“XML模式”和“编程模式”。
(一) 数据库模式
在数据库模式下,一个AdRotator链接到一个数据源。该数据源表格至少需要三个数据列:一个相应于图像的URL,一个相应于该图像被点击时要导航到的URL,一个相应于要在该图像的ALT标签中被显示的字符串。下列是数据源表格中的可用字段,其中后面几个是可选的:
列名称 | 数据类型 | 说明 |
ID | int | 这是主键。此列可给定任何名称。 |
ImageUrl | nvarchar(length) | 要作为广告显示的图像的相对或绝对URL。 |
NavigateUrl | nvarchar(length) | 广告的目标URL。如果没有提供值,则广告不是一个超链接。 |
AlternateText | nvarchar(length) | 找不到图像时显示的文本。有些浏览器中,该文本还会作为工具提示显示出来。替换文字也用于辅助功能,以便无法看到图形的用户可以听到大声读出的说明。 |
Keyword | nvarchar(length) | 可作为页筛选依据的广告类别,可选。 |
Impressions | int(4) | 一个指示广告的可能显示频率的数字。数字越大,显示该广告的频率越高。在XML文件中,所有Impressions值的总和不能超过2,048,000,000-1。可选。 |
Width | int(4) | 图像的宽度(以像素为单位),可选。 |
Height | int(4) | 图像的宽度(以像素为单位),可选。 |
【注意】上表中提供的数据类型是SQL Server类型。如果使用的是不同的数据库,请替换相应的合适类型。
当然,借助于ASP.NET 2.0强大的数据源数据处理功能,你并不需要一个类似这样的数据表格,你只要在DataSource本身使用一个SQL语句把该数据“拖入”到适当的结构中。比如说,如果你是动态地显示SQL Server 2005 AdventureWorks示例数据库ProductPhoto表格中图像的缩略图,并且允许在点击一下这个缩略图后能够重定向到在同一个表格中的LargePhoto图像(也是动态生成的)并且使用该产品表格中的一个描述来表示相应的可选文本,那么你可以象下列这样来使用:
<
asp:SqlDataSource ID
=
"
ProductPhotos
"
runat
=
"
server
"
ConnectionString
=
"
<%$ ConnectionStrings:AdventureWorksConnectionString %>
"
SelectCommand
=
"
SELECT Production.ProductPhoto.ProductPhotoID AS ID,
'
./ProductThumbNail.ashx?ID=
'
+
LTRIM(STR(Production.ProductPhoto.ProductPhotoID)) AS ImageUrl,
'
./ProductPhoto.ashx?ID=
'
+
LTRIM(STR(Production.ProductPhoto.ProductPhotoID)) AS NavigateUrl, Production.Product.Name AS AlternateText FROM Production.ProductPhoto INNER JOIN Production.ProductProductPhoto ON Production.ProductPhoto.ProductPhotoID
=
Production.ProductProductPhoto.ProductPhotoID INNER JOIN Production.Product ON Production.ProductProductPhoto.ProductID
=
Production.Product.ProductID
"
>
</
asp:SqlDataSource
>
上面的代码将产生一个具有四栏的结果集。之后,AdRotator控件看起来如下所示:
<
asp:AdRotator ID
=
"
AdRotator1
"
runat
=
"
server
"
DataSourceID
=
"
ProductPhotos
"
/>
这里的所有属性(除了DataSourceID及其名字外)都为其缺省值,因为我已经在DataSource的定义中使用缺省名来描述这些域。
(二) XML模式
另一种填充一个AdRotator的域的方式是使用一个静态XML文件,它有一个类似于表格模式的结构。本文下载源码中包含一个完整的示例。下面是一个简单摘要(一个称为Advertisments.xml的文件):
<
Ad
>
<
ImageUrl
>~/
ProductThumbNail.ashx
?
ID
=
70
</
ImageUrl
>
<
NavigateUrl
>~/
ProductPhoto.ashx
?
ID
=
70
</
NavigateUrl
>
<
AlternateText
>
Product Number
70
</
AlternateText
>
<
Impressions
>
100
</
Impressions
>
</
Ad
>
现在,该AdRotator看起来如下所示:
<
asp:AdRotator ID
=
"
AdRotator2
"
runat
=
"
server
"
AdvertisementFile
=
"
~/Advertisments.xml
"
/>
在此,我们也是使用了缺省值。
(三) 编程模式
无论AdRotator的AdCreated事件何时激发,都以编程方式填充该属性。此时,一个AdCreatedEventArgs对象被传递到事件处理器;而且你要设置三个属性:ImageURL,NavigateURL和AlternateText—它们都是用于生成控件之用的。
至此,该AdRotator控件看起来如下所示:
<
asp:AdRotator ID
=
"
AdRotator3
"
runat
=
"
server
"
OnAdCreated
=
"
AdRotator3_AdCreated
"
/>
在code-behind文件中,我仅绑定了一个事件处理器:
protected
void
AdRotator3_AdCreated(
object
sender, AdCreatedEventArgs e)
...
{ int ProductID = 1; e.ImageUrl = "~/ProductThumbNail.ashx?ID=" + ProductID.ToString(); e.NavigateUrl = "~/ProductPhoto.ashx?ID=" + ProductID.ToString(); e.AlternateText = "以编程方式从产品ID生成文本 " + ProductID.ToString(); }
这种情况可能非常有用。例如,你可以实现基于用户的导航历史,或基于他们已经实现的个性化或任何其它标准来实时的图像定位。
二、 动态图像生成问题
至此,我们已经分析了AdRotator类直接使用指向图像文件的URL,而不是字节流或二进制数组数据或任何其它可能描述一个图像的形式。当该图像以二进制数据形式存储在一个数据库文件中时,这就提出了一个问题。一般地,你是不想把它们写向磁盘的,因为它们将再次占用很多的空间并且需要与数据库版本保持同步。幸运的是,在Visual Studio 2005中,这一切变得相当容易。
从根本上看,我们需要创建一个HTTP处理器类,它将拦截到一个特定的URL的调用并且以一种浏览器期望的格式返回该图像。有关IHTTPHandler接口,在此不再赘述,请参考MSDN文档。HTTP处理器给你提供一种与低级请求和IIS Web服务器的响应服务交互的方式,并且提供一种很类似于ISAPI扩展的功能,只是使用一种更为简单的编程模型。
下面是其中一个处理器类(ProductThumbNail.ashx)相应的代码。其它的与此基本一致,除了使用一个不同的TableAdaptor来检索较大的图像外。
至此,我们已经分析了AdRotator类直接使用指向图像文件的URL,而不是字节流或二进制数组数据或任何其它可能描述一个图像的形式。当该图像以二进制数据形式存储在一个数据库文件中时,这就提出了一个问题。一般地,你是不想把它们写向磁盘的,因为它们将再次占用很多的空间并且需要与数据库版本保持同步。幸运的是,在Visual Studio 2005中,这一切变得相当容易。
从根本上看,我们需要创建一个HTTP处理器类,它将拦截到一个特定的URL的调用并且以一种浏览器期望的格式返回该图像。有关IHTTPHandler接口,在此不再赘述,请参考MSDN文档。HTTP处理器给你提供一种与低级请求和IIS Web服务器的响应服务交互的方式,并且提供一种很类似于ISAPI扩展的功能,只是使用一种更为简单的编程模型。
下面是其中一个处理器类(ProductThumbNail.ashx)相应的代码。其它的与此基本一致,除了使用一个不同的TableAdaptor来检索较大的图像外。
<%
@ 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 Proce***equest (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;} } }
在IHTTPHandler接口中实现的重要方法是Proce***equest()。它能使你以低级方式存取上下文对象;该上下文对象又进一步存取Request和Response对象以便你能够得到作为一个查询字符串传递到URL中的ID(借助于Request),并且借助于Response对象返回内容。返回的内容仅仅是一个从表格中的二进制栏中获取的字节数组。注意,我仅取得在第一行的ThumbNailPhoto栏中的内容并且把它转换为一个字节数组。
另外,为了往回发送图像,你只需要设置一下content type(注意,这可能来自于表格,或者由二进制形式的头部来动态决定),它负责告诉Response对象把数据“流回”,而不必等待数据流关闭,然后仅把字节数组写向输出流。
三、 小结
如今,大多数网站经常显示各式广告或邀请用户访问其他站点的类似动态内容。而ASP.NET 2.0中提供的AdRotator控件正可简化此任务。在当今IT广告世界里,这个小小的“精灵”控件将发挥越来越大的作用。
另外,为了往回发送图像,你只需要设置一下content type(注意,这可能来自于表格,或者由二进制形式的头部来动态决定),它负责告诉Response对象把数据“流回”,而不必等待数据流关闭,然后仅把字节数组写向输出流。
三、 小结
如今,大多数网站经常显示各式广告或邀请用户访问其他站点的类似动态内容。而ASP.NET 2.0中提供的AdRotator控件正可简化此任务。在当今IT广告世界里,这个小小的“精灵”控件将发挥越来越大的作用。