通常,应用程序可以将那些频繁访问的数据,以及那些需要大量处理时间来创建的数据存储在内存中,从而提高性能。例如,如果应用程序使用复杂的逻辑来处理大量数据,然后再将数据作为用户频繁访问的报表返回,避免在用户每次请求数据时重新创建报表可以提高效率。同样,如果应用程序包含一个处理复杂数据但不需要经常更新的页,则在每次请求时服务器都重新创建该页会使工作效率低下。
在这些情况下,为了帮助您提高应用程序的性能,ASP.NET 使用两种基本的缓存机制来提供缓存功能。第一种机制是应用程序缓存,它允许您缓存所生成的数据,如 DataSet 或自定义报表业务对象。第二种机制是页输出缓存,它保存页处理输出,并在用户再次请求该页时,重用所保存的输出,而不是再次处理该页。
应用程序缓存
应用程序缓存提供了一种编程方式,可通过键/值对将任意数据存储在内存中。使用应用程序缓存与使用应用程序状态类似。但是,与应用程序状态不同的是,应用程序缓存中的数据是易失的,即数据并不是在整个应用程序生命周期中都存储在内存中。使用应用程序缓存的优点是由 ASP.NET 管理缓存,它会在项过期、无效、或内存不足时移除缓存中的项。还可以配置应用程序缓存,以便在移除项时通知应用程序。有关更多信息,请参见缓存应用程序数据。
使用应用程序缓存的模式是,确定在访问某一项时该项是否存在于缓存中,如果存在,则使用。如果该项不存在,则可以重新创建该项,然后将其放回缓存中。这一模式可确保缓存中始终有最新的数据。
有关更多信息,请参见如何:检索缓存项的值。
页输出缓存
页输出缓存在内存中存储处理后的 ASP.NET 页的内容。这一机制允许 ASP.NET 向客户端发送页响应,而不必再次经过页处理生命周期。页输出缓存对于那些不经常更改,但需要大量处理才能创建的页特别有用。例如,如果创建大通信量的网页来显示不需要频繁更新的数据,页输出缓存则可以极大地提高该页的性能。可以分别为每个页配置页缓存,也可以在 Web.config 文件中创建缓存配置文件。利用缓存配置文件,只定义一次缓存设置就可以在多个页中使用这些设置。
页输出缓存提供了两种页缓存模型:整页缓存和部分页缓存。整页缓存允许将页的全部内容保存在内存中,并用于完成客户端请求。部分页缓存允许缓存页的部分内容,其他部分则为动态内容。有关更多信息,请参见缓存 ASP.NET 页。
部分页缓存可采用两种工作方式:控件缓存和缓存后替换。控件缓存有时也称为分段缓存,这种方式允许将信息包含在一个用户控件内,然后将该用户控件标记为可缓存的,以此来缓存页输出的部分内容。这一方式可缓存页中的特定内容,并不缓存整个页,因此每次都需重新创建整个页。例如,如果要创建一个显示大量动态内容(如股票信息)的页,其中有些部分为静态内容(如每周总结),这时可以将静态部分放在用户控件中,并允许缓存这些内容。
缓存后替换与控件缓存正好相反。这种方式缓存整个页,但页中的各段都是动态的。例如,如果要创建一个在规定时间段内为静态的页,则可以将整个页设置为进行缓存。如果向页添加一个显示用户名的 Label 控件,则对于每次页刷新和每个用户而言,Label 的内容都将保持不变,始终显示缓存该页之前请求该页的用户的姓名。但是,使用缓存后替换机制,可以将页配置为进行缓存,但将页的个别部分标记为不可缓存。在此情况下,可以向不可缓存部分添加 Label 控件,这样将为每个用户和每次页请求动态创建这些控件。有关更多信息,请参见缓存 ASP.NET 页的某些部分。
根据请求参数缓存页
除缓存页的单一版本外,ASP.NET 页输出缓存还提供了一些功能,可以创建根据请求参数的不同而不同的页的多个版本。有关更多信息,请参见缓存页的多个版本。
自动移除数据
出于以下原因之一,ASP.NET 可以从缓存中移除数据:
-
由于服务器上的内存不足,开始一个称为“清理”的过程。
-
由于缓存中的项已过期。
-
由于项的依赖项发生了更改。
为了帮助管理缓存项,在将项从缓存中移除时,ASP.NET 会通知应用程序。
清理
清理是在内存不足时从缓存中删除项的过程。如果某些项在一段时间内未被访问,或是在添加到缓存中时被标记为低优先级,则这些项会被移除。ASP.NET 使用 CacheItemPriority 对象来确定要首先清理的项。有关更多信息,请参见如何:将项添加到缓存中。
过期
除了清理外,在缓存项过期时,ASP.NET 会自动从缓存中移除这些项。向缓存添加项时,可以按下表中的描述设置其过期时间。
过期类型 | 说明 |
---|---|
可调过期 | 指定某项自上次被访问后多长时间过期。例如,可以将某项设置为自上次在缓存中被访问后 20 分钟过期。 |
绝对过期 | 指定某项在设定的时间过期,而不考虑访问频率。例如,可以将某项设置为在 6:00 PM 过期,或四小时后过期。 |
依赖项
可以将缓存中某一项的生存期配置为依赖于其他应用程序元素,如某个文件或数据库。当缓存项依赖的元素更改时,ASP.NET 将从缓存中移除该项。例如,如果您的网站显示一份报告,该报告是应用程序通过 XML 文件创建的,您可以将该报告放置在缓存中,并将其配置为依赖于该 XML 文件。当 XML 文件更改时,ASP.NET 会从缓存中移除该报告。当代码请求该报告时,代码会先确定该报告是否在缓存中,如果不在,代码会重新创建该报告。因此,始终都有最新版本的报告可用。
ASP.NET 缓存支持下表中描述的依赖项。
依赖项 | 说明 |
---|---|
键依赖项 | 应用程序缓存中的项存储在键/值对中。键依赖项允许项依赖于应用程序缓存中另一项的键。如果移除了原始项,则具有键依赖关系的项也会被移除。例如,可以添加一个名为 |
文件依赖项 | 缓存中的项依赖于外部文件。如果该文件被修改或删除,则缓存项也会被移除。 |
SQL 依赖项 | 缓存中的项依赖于 Microsoft SQL Server 2005、SQL Server 2000 或 SQL Server 7.0 数据库中表的更改。对于 SQL Server 2005,缓存中的项可依赖于表中的某一行。有关更多信息,请参见使用 SqlCacheDependency 类在 ASP.NET 中缓存。 |
聚合依赖项 | 通过使用 AggregateCacheDependency 类缓存中的项依赖于多个元素。如果任何依赖项发生更改,该项都会从缓存中移除。 |
自定义依赖项 | 可以用您自己的代码创建的依赖关系来配置缓存中的项。例如,可以创建一个自定义 Web 服务缓存依赖项,当调用 Web 服务得到一个特定值时,该依赖项就会从缓存中移除数据。 |
应用程序缓存项移除通知
当项从应用程序缓存中移除时,您可以收到通知。例如,如果有一个需要大量处理时间才能创建的项,当从缓存中移除该项时,您会收到通知以便可以立即替换该项。这样,下次请求该项时,用户便不必等待处理该项。有关更多信息,请参见如何:从缓存中移除项时通知应用程序。
(一)如何:检索缓存项的值
通过在 Cache 对象中进行检查来确定该项是否不为 null(在 Visual Basic 中为 Nothing)。如果该项存在,则将它分配给变量。否则,重新创建该项,将它添加到缓存中,然后访问它。
string cachedString;
cachedString = (string)Cache["CacheItem"];
if (cachedString == null)
{
cachedString = "Hello, World.";
Cache.Insert("CacheItem", cachedString);
}
(二)如何:将项添加到缓存中
可以使用 Cache 对象的 Insert 方法向应用程序缓存添加项。该方法向缓存添加项,并且通过几次重载,您可以用不同选项添加项,以设置依赖项、过期和移除通知。如果使用 Insert 方法向缓存添加项,并且已经存在与现有项同名的项,则缓存中的现有项将被替换
。
还可以使用 Add 方法向缓存添加项。使用此方法,您可以设置与 Insert 方法相同的所有选项;然而,Add 方法将返回您添加到缓存中的对象。另外,如果使用 Add 方法,并且缓存中已经存在与现有项同名的项,则该方法不会替换该项,并且不会引发异常。
1.通过键和值直接设置项向缓存添加项
通过指定项的键和值,像将项添加到字典中一样将其添加到缓存中。
下面的代码示例将名为 CacheItem1 的项添加到 Cache 对象中:
Cache["CacheItem1"] = "Cached Item 1";
2. 通过使用 Insert 方法将项添加到缓存中
调用 Insert 方法,传递要添加的项的键和值。
下面的代码示例添加名为 CacheItem2 的字符串:
Cache.Insert("CacheItem2", "Cached Item 2");
3.通过指定依赖项向缓存添加项
调用 Insert 方法,将 CacheDependency 对象的一个实例传递给该方法
下面的代码示例添加名为 CacheItem3 的项,该项依赖于缓存中名为 CacheItem2 的另一个项:
string[] dependencies = { "CacheItem2" };
Cache.Insert("CacheItem3", "Cached Item 3",
new System.Web.Caching.CacheDependency(null, dependencies));
下面的代码示例演示将名为 CacheItem4 的项添加到缓存中,并且在名为 XMLFile.xml 的文件上设置文件依赖项:
Cache.Insert("CacheItem4", "Cached Item 4",
new System.Web.Caching.CacheDependency(
Server.MapPath("XMLFile.xml")));
下面的代码示例演示如何创建多个依赖项。它向缓存中名为 CacheItem1 的另一个项添加键依赖项,向名为 XMLFile.xml 的文件添加文件依赖项。
System.Web.Caching.CacheDependency dep1 =
new System.Web.Caching.CacheDependency(Server.MapPath("XMLFile.xml"));
string[] keyDependencies2 = { "CacheItem1" };
System.Web.Caching.CacheDependency dep2 =
new System.Web.Caching.CacheDependency(null, keyDependencies2);
System.Web.Caching.AggregateCacheDependency aggDep =
new System.Web.Caching.AggregateCacheDependency();
aggDep.Add(dep1);
aggDep.Add(dep2);
Cache.Insert("CacheItem5", "Cached Item 5", aggDep);
4.将设有过期策略的项添加到缓存中
调用 Insert 方法,将绝对过期时间或弹性过期时间传递给该方法。
下面的代码示例将有一分钟绝对过期时间的项添加到缓存中:
Cache.Insert("CacheItem6", "Cached Item 6",
null, DateTime.Now.AddMinutes(1d),
System.Web.Caching.Cache.NoSlidingExpiration);
下面的代码示例将有 10 分钟弹性过期时间的项添加到缓存中:
Cache.Insert("CacheItem7", "Cached Item 7",
null, System.Web.Caching.Cache.NoAbsoluteExpiration,
new TimeSpan(0, 10, 0));
5.将设有优先级设置的项添加到缓存中
调用 Insert 方法,从 CacheItemPriority 枚举中指定一个值。
下面的代码示例将优先级值为 High 的项添加到缓存中:
Cache.Insert("CacheItem8", "Cached Item 8",
null, System.Web.Caching.Cache.NoAbsoluteExpiration,
System.Web.Caching.Cache.NoSlidingExpiration,
System.Web.Caching.CacheItemPriority.High, null);
6.使用 Add 方法向缓存添加项
调用 Add 方法,它返回一个表示项的对象。
下面的代码示例向缓存添加名为 CacheItem9 的项,同时将变量 CachedItem9 的值设置为已添加的项。
string CachedItem9 = (string)Cache.Add("CacheItem9",
"Cached Item 9", null,
System.Web.Caching.Cache.NoAbsoluteExpiration,
System.Web.Caching.Cache.NoSlidingExpiration,
System.Web.Caching.CacheItemPriority.Default,
null);
(三)使用SqlCacheDependency 类缓存
ASP.NET 允许您使用 SqlCacheDependency 类创建依赖于数据库中表或行的缓存项。当表中或特定行中发生更改时,带有依赖项的项便会失效,并会从缓存中移除。可以在 Microsoft SQL Server 7.0、SQL Server 2000 和 SQL Server 2005 中设置表的依赖项。如果您使用 SQL Server 2005,还可以设置特定记录的依赖项。
1.SQL Server 7.0 和 SQL Server 2000 的实现-轮询模型
ASP.NET 为 SQL Server 7.0 和 SQL Server 2000 的缓存依赖项实现了一个轮询模型。ASP.NET 进程内的一个线程会以指定的时间间隔轮询 SQL Server 数据库,以确定数据是否已更改。如果数据已更改,缓存依赖项便会失效,并从缓存中移除。可以在 Web.config 文件中以声明方式指定应用程序中的轮询间隔,也可以使用 SqlCacheDependency 类以编程方式指定此间隔。
为了在 SQL Server 7.0 和 SQL Server 2000 中使用 SQL 缓存依赖项,必须先将 SQL Server 配置为支持缓存依赖项。ASP.NET 提供了一些实用工具,可用于配置 SQL Server 上的 SQL 缓存,其中包括一个名为 Aspnet_regsql.exe 的工具和 SqlCacheDependencyAdmin 类。
2. SQL Server 2005 实现-发布订阅机制
SQL Server 2005 为缓存依赖项实现的模型不同于 SQL Server 7.0 和 SQL Server 2000 中的缓存依赖项模型。在 SQL Server 2005 中,不需要执行任何特殊的配置步骤来启用 SQL 缓存依赖项。此外,SQL Server 2005 还实现了一种更改通知模型,可以向订阅了通知的应用程序服务器发送通知,而不是依赖早期版本的 SQL Server 中必需的轮询模型。
(四)System.Web.Caching 命名空间
System.Web.Caching 命名空间提供用于缓存服务器上常用数据的类。这包括 Cache 类,该类是一个使您可以存储任意数据对象(如哈希表和数据集)的词典。它还为这些对象提供到期功能,并提供使您可以添加和移除对象的方法。您还可以添加依赖于其他文件或缓存项的对象,并在从 Cache 中移除对象时执行回调以通知应用程序。
以声明的方式控制 ASP.NET 页或页中包含的用户控件的输出缓存策略。有关输出缓存的更多信息,请参见 ASP.NET 缓存功能。
<%@ OutputCache Duration="#ofseconds" Location="Any | Client | Downstream | Server | None | ServerAndClient " Shared="True | False" VaryByControl="controlname" VaryByCustom="browser | customstring" VaryByHeader="headers" VaryByParam="parametername" CacheProfile="cache profile name | ''" NoStore="true | false" SqlDependency="database/table name pair | CommandNotification" %>
-
Duration
-
页或用户控件进行缓存的时间(以秒计)。在页或用户控件上设置该属性为来自对象的 HTTP 响应建立了一个过期策略,并将自动缓存页或用户控件输出。
注意 这是必选属性。如果未包含该属性,将出现分析器错误。
-
Location
-
OutputCacheLocation 枚举值之一。默认值为 Any。
注意 包含在用户控件(.ascx 文件)中的 @ OutputCache 指令不支持此属性。
-
CacheProfile
-
与该页关联的缓存设置的名称。这是可选属性,默认值为空字符 ("")。
注意 包含在用户控件(.ascx 文件)中的 @ OutputCache 指令不支持此属性。在页中指定此属性时,属性值必须与 outputCacheSettings 节下面的 outputCacheProfiles 元素中的一个可用项的名称匹配。如果此名称与配置文件项不匹配,将引发异常。
-
NoStore
-
一个布尔值,它决定了是否阻止敏感信息的二级存储。
注意 包含在用户控件(.ascx 文件)中的 @ OutputCache 指令不支持此属性。将此属性设置为 true 等效于在请求期间执行以下代码:
Response.Cache.SetNoStore();
-
Shared
-
一个布尔值,确定用户控件输出是否可以由多个页共享。默认值为 false。有关更多信息,请参见备注部分。
注意 包含在 ASP.NET 页(.aspx 文件)中的 @ OutputCache 指令不支持此属性。
-
SqlDependency
-
标识一组数据库/表名称对的字符串值,页或控件的输出缓存依赖于这些名称对。请注意,SqlCacheDependency 类监视输出缓存所依赖的数据库中的表,因此当更新表中的项时,使用基于表的轮询时将从缓存中移除这些项。将通知(在 Microsoft SQL Server 2005 中)与 CommandNotification 值一起使用时,最终将使用 SqlDependency 类向 SQL Server 2005 服务器注册查询通知。
注意 SqlDependency 属性的 CommandNotification 值仅在网页 (.aspx) 中有效。用户控件只能将基于表的轮询用于 @ OutputCache 指令。
-
VaryByCustom
-
表示自定义输出缓存要求的任意文本。如果赋予该属性的值为 browser,缓存将随浏览器名称和主要版本信息的不同而异。如果输入自定义字符串,则必须在应用程序的 Global.asax 文件中重写 GetVaryByCustomString 方法。
-
VaryByHeader
-
分号分隔的 HTTP 标头列表,用于使输出缓存发生变化。将该属性设为多标头时,对于每个指定标头组合,输出缓存都包含一个不同版本的请求文档。
注意 设置 VaryByHeader 属性将启用在所有 HTTP 1.1 版缓存中缓存项,而不仅仅在 ASP.NET 缓存中进行缓存。用户控件中的 @ OutputCache 指令不支持此属性。
-
VaryByParam
-
分号分隔的字符串列表,用于使输出缓存发生变化。默认情况下,这些字符串与随 GET 方法属性发送的查询字符串值对应,或与使用 POST 方法发送的参数对应。将该属性设置为多个参数时,对于每个指定参数组合,输出缓存都包含一个不同版本的请求文档。可能的值包括 none、星号 (*) 以及任何有效的查询字符串或 POST 参数名称。
警告 在 ASP.NET 页和用户控件上使用 @ OutputCache 指令时,需要该属性或 VaryByControl 属性。如果没有包含它,则发生分析器错误。如果不希望通过指定参数来改变缓存内容,请将值设置为 none。如果希望通过所有的参数值改变输出缓存,请将属性设置为星号 (*))。
-
VaryByControl
-
一个分号分隔的字符串列表,用于更改用户控件的输出缓存。这些字符串代表用户控件中声明的 ASP.NET 服务器控件的 ID 属性值。有关更多信息,请参见缓存 ASP.NET 页的某些部分。
注意 在 ASP.NET 页和用户控件上使用 @ OutputCache 指令时,需要该属性或 VaryByParam 属性。
设置页输出缓存的值与通过 Cache 属性操作 SetExpires 和 SetCacheability 方法的过程相同。
如果 Web 窗体页要求用户查看授权,则输出缓存将 Cache-Control HTTP 标头设置为 private。有关所有这些主题的更多信息,请参见缓存 ASP.NET 页。
如果将 Shared 属性设置为 true,则多个 Web 窗体页可以访问缓存的用户控件输出。如果不将该属性设置为 true,默认行为是为包含用户控件的每一页缓存用户控件输出的一个版本。通过启用 Shared 属性,可能可以节省大量内存。有关更多信息,请参见缓存 ASP.NET 页的某些部分。
下面的代码示例演示如何设置页或用户控件进行输出缓存的持续时间。
<%@ OutputCache Duration="100" VaryByParam="none" %>
下一个代码示例演示如何指示输出缓存按页或用户控件的位置对它们进行缓存,并根据窗体的 POST 方法或查询字符串对窗体参数进行计数。每个收到的具有不同位置或计数参数(或两者)的 HTTP 请求都进行 10 秒的缓存处理。带有相同参数值的任何后继请求都将从缓存中得到满足,直至超过输入的缓存期。
<%@ OutputCache Duration="10" VaryByParam="location;count" %>
(六)缓存 ASP.NET 页的某些部分
有时缓存整个页是不现实的,因为页的某些部分可能在每次请求时都需要更改。在这些情况下,只能缓存页的一部分。执行此操作有两个选项:控件缓存和缓存后替换。
在控件缓存(也称为片段缓存)中,可以通过创建用户控件来包含缓存的内容,然后将用户控件标记为可缓存来缓存部分页输出。该选项允许缓存页中的特定内容,而在每次都重新创建整个页。例如,如果创建的页显示大量动态内容(如股票信息),但也有某些部分是静态的(如每周摘要),则可以在用户控件中创建这些静态部分并将用户控件配置为缓存。
缓存后替换与控件缓存正好相反。它对页进行缓存,但是页中的某些片段是动态的,因此不会缓存这些片段。例如,如果创建的页在设定的时间段内完全是静态的(例如新闻报道页),可以设置为缓存整个页。如果为缓存的页添加旋转广告横幅,则在页请求之间,广告横幅不会变化。然而,使用缓存后替换,可以对页进行缓存,但可以将特定部分标记为不可缓存。在本例中,将广告横幅标记为不可缓存。它们将在每次页请求时动态创建,并添加到缓存的页输出中。有关缓存后替换的更多信息,请参阅动态更新缓存页的部分。
控件缓存
通过创建用户控件来缓存内容,可以将页上需要花费宝贵的处理器时间来创建的某些部分(例如数据库查询)与页的其他部分分离开。只需占用很少服务器资源的部分可以在每次请求时动态生成。
在标识了要缓存的页的部分,并创建了用以包含这些部分中的每个部分的用户控件后,您必须确定这些用户控件的缓存策略。您可以使用 @ OutputCache 指令,或者在代码中使用 PartialCachingAttribute 类,以声明的方式为用户控件设置这些策略。
例如,如果在用户控件文件(.ascx 文件)的顶部包括下面的指令,则该控件的一个版本将在输出缓存中存储 120 秒。
<%@ OutputCache Duration="120" VaryByParam="None" %>若要在代码中设置缓存参数,可以在用户控件的类声明中使用一个属性。例如,如果在类声明的元数据中包括下面的属性,则该内容的一个版本将在输出缓存中存储 120 秒:
C# 复制到剪贴板[PartialCaching(120)] public partial class CachedControl : System.Web.UI.UserControl { // Class Code }有关可在页输出中设置的属性的更多信息,请参阅 @ OutputCache 主题。有关如何开发用户控件的更多信息,请参见 ASP.NET Web 服务器控件概述。
注意 由于可在页上嵌套用户控件,您还可以嵌套已放置到输出缓存中的用户控件。可以为页和嵌套的用户控件指定不同的缓存设置。
以编程方式引用缓存的用户控件
在以声明的方式创建可缓存的用户控件时,可以包括一个 ID 属性,以便以编程方式引用该用户控件实例。但是,在代码中引用用户控件之前,必须验证在输出缓存中是否存在该用户控件。缓存的用户控件只在首次请求时动态生成;在指定的时间到期之前,从输出缓存满足所有的后续请求。确定用户控件已实例化后,可以从包含页以编程方式操作该用户控件。例如,如果通过声明方式将
SampleUserControl
的 ID 分配给用户控件,则可以使用下面的代码检查它是否存在。C# 复制到剪贴板protected void Page_Load(object sender, EventArgs e) { if (SampleUserControl != null) // Place code manipulating SampleUserControl here. }以不同的持续时间缓存页和用户控件
(七)以声明方式设置 ASP.NET 页的可缓存性可以为页和页上的用户控件设置不同的输出缓存持续时间值。如果页的输出缓存持续时间长于用户控件的输出缓存持续时间,则页的输出缓存持续时间优先。例如,如果页的输出缓存设置为 100 秒,而用户控件的输出缓存设置为 50 秒,则包括用户控件在内的整个页将在输出缓存中存储 100 秒,而与用户控件较短的时间设置无关。
下面的代码示例演示了当页的缓存持续时间长于用户控件的缓存持续时间时的效果。该页配置为缓存 100 秒。
C# 复制到剪贴板<%@ Page language="C#" %> <%@ Register tagprefix="SampleControl" tagname="Time" src="uc01.ascx" %> <%@ OutputCache duration="100" varybyparam="none" %> <SampleControl:Time runat="server" /><br /> <br /> <br /> This page was most recently generated at:<p> <% DateTime t = DateTime.Now.ToString(); Response.Write(t); %>下面的代码示例演示了包括在页中的用户控件。控件的缓存持续时间设置为 50 秒。
C# 复制到剪贴板<% @Control language="C#" %> <% @OutputCache duration="50" varybyparam="none" %> This user control was most recently generated at:<p> <% DateTime t = DateTime.Now.ToString(); Response.Write(t); %>不过,如果页的输出缓存持续时间比用户控件的输出缓存持续时间短,则即使已为某个请求重新生成该页的其余部分,也将一直缓存用户控件直到其持续时间到期为止。例如,如果页的输出缓存设置为 50 秒,而用户控件的输出缓存设置为 100 秒,则页的其余部分每到期两次,用户控件才到期一次。
下面的代码演示了一个页的标记,该页中包含的用户控件的缓存持续时间长于该页的缓存持续时间。该页配置为缓存 50 秒。
C# 复制到剪贴板<%@ Page language="C#" %> <%@ Register tagprefix="SampleControl" tagname="Time" src="uc2.ascx" %> <%@ OutputCache duration="50" varybyparam="none" %> <SampleControl:Time runat="server" /><br /> <br /> <br /> This page was most recently generated at:<p> <% DateTime t = DateTime.Now.ToString(); Response.Write(t); %>下面的代码演示了包括在页中的用户控件。控件的缓存持续时间设置为 100 秒。
C# 复制到剪贴板<% @Control language="C#" %> <% @OutputCache duration="100" varybyparam="none" %> This user control was most recently generated at:<p> <% DateTime t = DateTime.Now.ToString(); Response.Write(t); %>
设置页的可缓存性
页或用户控件的可缓存性是指是否可以在页的响应生命周期内在设备上缓存页。可缓存页的设备包括发出请求的浏览器、响应请求的 Web 服务器以及请求或响应流中其他任何具有缓存功能的设备,如代理服务器。
当 Web 服务器向请求浏览器发送响应时,服务器会在响应的 HTTP 头中包含一个 Cache-Control 字段,该字段定义可以缓存该页的设备。根据您应用程序的需要,可以分别定义哪些设备应该或不应缓存各个 ASP.NET 页。例如,您可能希望用户登录页的可缓存性设置不同于显示产品选择的目录页的对应设置。对于登录页,出于安全方面的考虑,您可能希望只将页缓存到服务器上,而目录页可以缓存到任何设备上。
对于 ASP.NET 页,可以使用 HttpCacheability 枚举中的值设置可缓存性。该枚举具有下列值。前三个值与 Cache-Control HTTP 头设置直接对应,后三个值为特殊值。
NoCache 指定发出请求的设备每次应从 Web 服务器获取响应。
Public 允许由客户端和共享(代理)缓存来缓存响应。
Private 指定响应只能在客户端上缓存,而不能由共享(代理服务器)缓存来缓存。
Server 指定仅在原始服务器上缓存响应。
ServerAndNoCache 应用 Server 和 NoCache 两者的设置,以指示在该服务器上缓存内容,但显式拒绝其他所有服务器缓存响应的功能。
ServerAndPrivate 指定仅在原始服务器和请求客户端上缓存响应;不允许代理服务器缓存响应。
您可以通过在 @ OutputCache 指令中包含 Location 属性并指定 OutputCacheLocation 枚举值之一,以声明的方式设置页的可缓存性。还可以使用 SetCacheability 方法为页指定 HttpCacheability 值,从而以编程方式设置该页的可缓存性。可以通过 Response 类的 Cache 属性访问该方法。
在页中包含 @ OutputCache 指令,并定义 Duration 和 VaryByParam 属性。
在 @ OutputCache 指令中包含 Location 属性,并将其值定义为 OutputCacheLocation 枚举中的下列值之一:Any、Client、Downstream、Server、ServerAndClient 或 None。
下面的代码演示如何将页的可缓存性设置为 60 秒:
<%@ OutputCache Duration="60" VaryByParam="None"%>
注意 默认设置为 Any。如果未定义 Location 属性,则可以将页输出缓存在与响应有关的所有具有缓存功能的网络设备上。其中包括请求客户端、原服务器、以及响应通过的任何代理服务器。
使用缓存配置文件以声明方式设置页的可缓存性
(八)以编程方式设置页的可缓存性
在应用程序的 Web.config 文件中定义缓存配置文件,在配置文件中包括 duration 和 varyByParam 设置。
下面的 <caching> 配置元素定义名为
Cache30Seconds
的缓存配置文件,它将在服务器上将页缓存 30 秒之久。<caching> <outputCacheSettings> <outputCacheProfiles> <add name="Cache30Seconds" duration="30" varyByParam="none" /> </outputCacheProfiles> </outputCacheSettings> </caching>在使用配置文件的每个 ASP.NET 页中包含 @ OutputCache 指令,并将 CacheProfile 属性设置为 Web.config 文件中定义的缓存配置文件的名称。
下面的代码指定页应当使用名为
Cache30Seconds
的缓存配置文件:复制到剪贴板<%@ OutputCache CacheProfile="Cache30Seconds" %>
在页的代码中,调用 Response 对象的 Cache 属性的 SetCacheability 方法。
下面的代码将 Cache-Control HTTP 标头设置为 Public。
如果将 NoCache 或 ServerAndNoCache 传递到 SetCacheability 方法以防止请求的浏览器在它自己的历史记录文件夹中缓存某一页,那么任何时候当某个用户单击“后退”或“前进”按钮时,都会请求响应的新版本。通过调用 Cache 属性的 SetAllowResponseInBrowserHistory 方法,并且为 allow 参数传递 true 值,您可以按条件重写此行为。
如果将可缓存性设置为除 NoCache 或 ServerAndNoCache 之外的任何值,ASP.NET 将忽略由 SetAllowResponseInBrowserHistory 方法设置的值。
(九)设置 ASP.NET 页缓存的过期时间值
若要导致某一页添加到输出缓存中,需要为该页建立到期策略。这可以通过以声明方式或编程方式来实现。
以声明方式为页设置输出缓存到期时间
-
将 @ OutputCache 指令包括在您要缓存其响应的 ASP.NET 页(.aspx 文件)中。将 Duration 属性设置为一个正数值,将 VaryByParam 属性设置为一个值。
注意 默认情况下,@ OutputCache 指令将 Cache-Control 标头设置为 Any。
例如,下面的 @ OutputCache 指令将页的到期时间设置为 60 秒:
<%@ OutputCache Duration="60" VaryByParam="None" %>
注意 在使用 @ OutputCache 指令时,必须包括一个 VaryByParam 属性,否则将出现分析器错误。如果不希望使用 VaryByParam 属性提供的功能,请将它的值设置为“None”。有关更多信息,请参见缓存页的多个版本。
以编程方式为页设置输出缓存到期时间
-
在该页的代码中,在 Response 对象的 Cache 属性中设置该页的到期策略。
注意 如果以编程方式设置页的到期时间,则您还必须为缓存的页设置 Cache-Control 标头。为此,请调用 SetCacheability 方法并向其传递 HttpCacheability 枚举值 Public。
下面的代码示例设置与前面过程中的 @ OutputCache 指令相同的缓存策略。
C# 复制到剪贴板Response.Cache.SetExpires(DateTime.Now.AddSeconds(60)); Response.Cache.SetCacheability(HttpCacheability.Public); Response.Cache.SetValidUntilExpires(true);
当缓存页到期时,以后对该页的请求将导致动态生成的响应。会在指定的持续时间内缓存该响应页。
(十)动态更新缓存页的部分
对页面进行缓存可以大大提高 Web 应用程序的性能。不过,在有些情况下,需要缓存页面的大部分内容,但页面中的某些片段是动态的。例如,如果创建一个页面,其中的新闻故事在设定时间段内完全是静态的,则可以设置为缓存整个页面。如果希望提供在每次页请求时都发生变化的交替出现的广告横幅,则该页中包含该广告的部分需要是动态的。
若要允许缓存某个页面但动态地替换其中的某些内容,可以使用 ASP.NET 缓存后替换。通过使用缓存后替换,将对整个页面进行输出缓存,并将特定的部分标记为不进行缓存。在广告横幅示例中,AdRotator 控件使您可以利用缓存后替换功能,以便为每个用户及在每次刷新页时动态创建广告。
有三种方法可以实现缓存后替换:
-
以声明方式使用 Substitution 控件。
-
以编程方式使用 Substitution 控件 API。
-
以隐式方式使用 AdRotator 控件。
Substitution 控件
ASP.NET Substitution 控件指定缓存页中动态创建而不进行缓存的部分。将 Substitution 控件放置在该页上要显示动态内容的位置。
在运行时,Substitution 控件调用使用 MethodName 属性指定的方法。该方法必须返回一个字符串,然后该字符串替换 Substitution 控件的内容。该方法必须是 Page 或 UserControl 包含控件上的静态方法。
使用 Substitution 控件可以将客户端可缓存性更改为服务器可缓存性,以便该页面不会在客户端上进行缓存。这样可以确保以后对该页的请求能够再次调用该方法以生成动态内容。
Substitution API
若要以编程方式为缓存页创建动态内容,可以在页代码中将某个方法的名称作为参数传递给 WriteSubstitution 方法来调用该方法。该方法处理动态内容的创建,它采用单个 HttpContext 参数并返回一个字符串。该返回字符串是将在给定位置被替换的内容。通过调用 WriteSubstitution 方法来代替以声明方式使用 Substitution 控件的一个好处是可以调用任意对象的方法,而不只是调用 Page 或 UserControl 对象的静态方法。
调用 WriteSubstitution 方法可以将客户端可缓存性更改为服务器可缓存性,以便该页不会在客户端上进行缓存。这样可以确保以后对该页的请求能够再次调用该方法以生成动态内容。
AdRotator 控件
AdRotator 服务器控件在内部实现对缓存后替换的支持。如果将 AdRotator 控件放在页面上,则无论是否缓存父页,都将在每次请求时呈现其特有的广告。因此,包含 AdRotator 控件的页面只在服务器端进行缓存。
(十一)ASP.NET 2.0 中改进的缓存功能
摘要:本文中,Stephen Walther 将重点介绍 ASP.NET 2.0 中新增的缓存功能,以及如何使用这些新功能改进 ASP.NET 应用程序的性能和可扩展性。(本文包含一些指向英文站点的链接。)
本页内容
更轻松的数据缓存 | |
使用 SQL Cache Invalidation | |
使用 Post-Cache Substitution | |
结论 |
对于由数据库驱动的 Web 应用程序来说,要改进其性能,最好的方法就是使用缓存。从数据库中检索数据可能是您在 Web 站点上执行的最慢的操作之一。如果能够将数据库中的数据缓存到内存中,就无需在请求每个页面时都访问数据库,从而可以大大提高应用程序的性能。
缓存有一个且只有一个缺点,那就是数据过期的问题。如果将数据库表的内容缓存到内存中,当基础数据库表中的记录发生更改时,您的 Web 应用程序将显示过期的、不准确的数据。对于某些类型的数据,即便显示的数据稍微有些过期,影响也不会太大;但对于诸如股票价格和竞拍出价之类的数据,即使显示的数据稍微有些过期也是不可接受的。
Microsoft ASP.NET 1.0 Framework 没有针对此问题提供一个完善的解决方案。使用 ASP.NET 1.0 Framework 时,您不得不在性能和数据过期之间作出权衡。幸运的是,Microsoft ASP.NET 2.0 Framework 提供了一项新功能,称为 SQL Cache Invalidation,可以解决这一棘手的问题。
在本文中,您将进一步了解 ASP.NET 2.0 Framework 中许多新的缓存改进功能。首先,您将了解到如何在新增的 DataSource 控件中集成缓存支持。然后,您将了解到如何配置和使用 SQL Cache Invalidation。最后,您将了解到随 ASP.NET 2.0 Framework 引入的一个新控件:Substitution 控件,使用该控件可以向已缓存的页面中插入动态内容。
更轻松的数据缓存
在 ASP.NET 2.0 Framework 中,最大的变化之一就是在 ASP.NET 页面上访问数据库数据的方式发生了变化。ASP.NET 2.0 Framework 包含一组新的控件,统称为 DataSource 控件。您可以使用这些控件来表示数据源,例如数据库或 XML 文件。
在 ASP.NET 1.0 Framework 中,是通过将控件绑定到 DataSet 或 DataReader,使用控件来显示数据库数据的。而在 ASP.NET 2.0 Framework 中,通常是将控件绑定到 DataSource 控件。通过 DataSource 控件,您可以创建显示数据库数据的 ASP.NET 页面,而不用为访问数据库编写任何代码。
在处理数据库数据时,通常使用下列三个 DataSource 控件中的一个控件:
• | SqlDataSource — 表示 SQL 数据源,例如 Microsoft SQL Server 或 Oracle 数据库。 |
• | AccessDataSource — 一个专用的 SqlDataSource 控件,用于 Microsoft Access 数据库。 |
• | ObjectDataSource — 表示充当数据源的自定义业务对象。 |
例如,假设您要在 DropDownList 控件中显示从数据库中检索到的书目列表(参见图 1)。列表 1 中的页面说明了如何将 DropDownList 控件绑定到 SqlDataSource 控件。
图 1:使用 SqlDataSource 控件检索数据
列表 1:DisplayTitles.aspx
<html> <head runat="server"> <title>Display Titles</title> </head> <body> <form id="form1" runat="server"> <asp:DropDownList ID="DropDownList1" DataSourceId="SqlDataSource1" DataTextField="Title" Runat="server" /> <asp:SqlDataSource ID="SqlDataSource1" ConnectionString="Server=localhost;database=Pubs" SelectCommand="SELECT Title FROM Titles" Runat="server" /> </form> </body> </html>
请注意,列表 1 中的 SqlDataSource 控件用于提供连接字符串,SQL SELECT 命令用于从数据库中检索记录。DropDownList 控件通过其 DataSourceID 属性绑定到 SqlDataSource 控件。
使用 DataSource 控件缓存数据
使用 DataSource 控件,不仅可以更轻松地连接数据库,还使缓存数据库数据变得更容易。只需在 SqlDataSource 控件上设置一两个属性,就可以自动在内存中缓存由 DataSource 控件表示的数据。
例如,如果要将 Titles 数据库表在内存中缓存至少 10 分钟,可以按照以下方式声明 SqlDataSource 控件。
<asp:SqlDataSource ID="SqlDataSource1" EnableCaching="true" CacheDuration="600" ConnectionString="Server=localhost;database=Pubs" SelectCommand="SELECT Title FROM Titles" Runat="server" />
如果 EnableCaching 属性的值为 true,SqlDataSource 将自动缓存通过 SelectCommand 检索到的数据。使用 CacheDuration 属性,可以指定从数据库中刷新数据之前缓存数据的时间(以秒为单位)。
默认情况下,SqlDataSource 使用绝对过期策略来缓存数据,即每隔指定的秒数就从数据库中刷新一次。此外,您还可以选择使用可变过期策略。如果将 SqlDataSource 配置为使用可变过期策略,那么只要持续访问数据,数据就不会过期。如果需要缓存大量项目,使用可变过期策略将非常有用,因为这种过期策略将只在内存中保留访问最频繁的项目。
例如,下面的 SqlDataSourceControl 被配置为使用可变过期策略,过期时间为 10 分钟。
<asp:SqlDataSource ID="SqlDataSource1" EnableCaching="true" CacheExpirationPolicy="Sliding" CacheDuration="600" ConnectionString="Server=localhost;database=Pubs" SelectCommand="SELECT Title FROM Titles" Runat="server" />
由于 CacheExpirationPolicy 属性的值被设置为 Sliding,CacheDuration 属性的值被设置为 600,因此,只要在 10 分钟内持续访问,此 SqlDataSource 表示的数据就会一直保留在内存中。
使用 SQL Cache Invalidation
SQL Cache Invalidation 是 ASP.NET 2.0 Framework 最值得期待的新增功能之一。使用 SQL Cache Invalidation 可以获得缓存的全部性能优势,而不用担心数据过期的问题。SQL Cache Invalidation 使您可以在基础数据库中的数据发生更改时自动更新缓存中的数据。
SQL Cache Invalidation 通过在后台不断轮询数据库来检查数据更改。每隔一定的时间(毫秒),ASP.NET Framework 就会检查数据库中是否存在更新。如果 ASP.NET Framework 检测到任何更改,将从缓存中删除从数据库中添加的、依赖于数据库的任何项目(即,这些项目将过期)。
注意:Microsoft SQL Server 2005 支持一种截然不同的 SQL Cache Invalidation 方法。您可以配置 SQL Server 2005,使其在数据库、数据库表或数据库行发生变化时通知 ASP.NET 应用程序。这样,ASP.NET Framework 就不需要通过不断轮询 SQL Server 2005 数据库来检查数据更改了。
需要注意的是,SQL Cache Invalidation 只能用于 Microsoft SQL Server 7 及更高版本,不能用于其他数据库,例如 Microsoft Access 或 Oracle。
在缓存整个页面的输出、使用 DataSource控件或直接使用 Cache 对象时,都可以使用 SQL Cache Invalidation。下面将分别介绍这三种情况。
配置 SQL Cache Invalidation
在 Web 应用程序中使用 SQL Cache Invalidation 之前,首先必须执行一些配置步骤。必须将 Microsoft SQL Server 配置为支持 SQL Cache Invalidation,还必须在应用程序的 Web 配置文件中添加必要的配置信息。
可以按照以下两种方法配置 SQL Server:使用 aspnet_regsql 命令行工具,或者使用 SqlCacheDependencyAdmin 类。
使用 ASPNET_REQSQL 启用 SQL Cache Invalidation
使用 aspnet_regsql 工具,您可以通过命令行来配置 SQL Cache Invalidation。aspnet_regsql 工具位于 Windows/Microsoft.NET/Framework/[版本] 文件夹中。要使用此工具,必须打开命令提示符窗口并浏览到此文件夹。
要在使用 Pubs 数据库时支持 SQL Cache Invalidation,需要执行以下命令。
aspnet_regsql -E -d Pubs -ed
-E 选项使 aspnet_regsql 工具在连接到数据库服务器时使用集成的安全设置。-d 选项用于选择 Pubs 数据库。最后,-ed 选项用于为数据库启用 SQL Cache Invalidation。
执行此命令时,将在数据库中添加一个名为 AspNet_SqlCacheTablesForChangeNotification 的新数据库表。此表包含启用了 SQL Cache Invalidation 的所有数据库表的列表。此命令还将在数据库中添加一组存储过程。
为数据库启用 SQL Cache Invalidation 后,必须从数据库中选择要启用 SQL Cache Invalidation 的特定表。以下命令将为 Titles 数据库表启用 SQL Cache Invalidation。
aspnet_regsql -E -d Pubs -t Titles -et
-t 选项用于选择数据库表。-et 选项为数据库表启用 SQL Cache Invalidation。当然,您可以通过对每个数据库表重复执行此命令,为多个表启用 SQL Cache Invalidation。
执行此命令时,将在数据库表中添加一个触发器。只要您对表进行了修改,此触发器就将触发并更新 AspNet_SqlCacheTablesForChangeNotification 表。
最后,要获取某个特定数据库中当前启用了 SQL Cache Invalidation 的表的列表,可以使用以下命令。
aspnet_regsql -E -d Pubs -lt
此方法将从 AspNet_SqlCacheTablesForChangeNotification 中选择表的列表。此外,您也可以通过直接在该数据库表中执行查询来检索此信息。
使用 SqlCacheDependencyAdmin 类
aspnet_regsql 工具在后台使用 SqlCacheDependencyAdmin 类的方法来配置 Microsoft SQL Server。如果您愿意,可以直接从 ASP.NET 页面中使用此类的方法。
SqlCacheDependencyAdmin 类具有五个重要的方法:
• | DisableNotifications — 为特定数据库禁用 SQL Cache Invalidation。 |
• | DisableTableForNotifications — 为数据库中的特定表禁用 SQL Cache Invalidation。 |
• | EnableNotifications — 为特定数据库启用 SQL Cache Invalidation。 |
• | EnableTableForNotifications — 为数据库中的特定表启用 SQL Cache Invalidation。 |
• | GetTablesEnabledForNotifications — 返回启用了 SQL Cache Invalidation 的所有表的列表。 |
例如,使用列表 2 中的 ASP.NET 页面,您可以为 Pubs 数据库中的任何表配置 SQL Cache Invalidation(参见图 2)。
图 2:从 ASP.NET 页面中启用 SQL Cache Invalidation
列表 2:EnableSCI.aspx (C#)
<%@ Page Language="c#" %> <%@ Import Namespace="System.Web.Caching" %> <script runat="server"> const string connectionString = "Server=localhost;Database=Pubs"; void Page_Load() { if (!IsPostBack) { SqlCacheDependencyAdmin.EnableNotifications( connectionString); SqlDataSource1.SelectParameters.Add("connectionString", connectionString); } } void EnableTable(Object s, EventArgs e) { try { SqlCacheDependencyAdmin.EnableTableForNotifications( connectionString, txtTableName.Text); } catch (Exception ex) { lblErrorMessage.Text = ex.Message; } txtTableName.Text = ""; } </script> <html> <head runat="server"> <title>Enable SQL Cache Invalidation</title> </head> <body> <form id="form1" runat="server"> <h1>SQL Cache Invalidation</h1>
以下表格已启用 SQL Cache Invalidation:
<p> <asp:GridView id="grdTables" DataSourceID="SqlDataSource1" CellPadding="10" ShowHeader="false" Runat="Server" /> </p> <asp:ObjectDataSource ID="SqlDataSource1" TypeName="System.Web.Caching.SqlCacheDependencyAdmin" SelectMethod="GetTablesEnabledForNotifications" Runat="Server" /> <p> <asp:Label ID="lblErrorMessage" EnableViewState="false" ForeColor="red" Runat="Server" /> </p> <asp:TextBox ID="txtTableName" Runat="Server" /> <asp:Button Text="Enable Table" OnClick="EnableTable" Runat="Server" /> </form> </body> </html>
列表 2:EnableSCI.aspx (Visual Basic .NET)
<%@ Page Language="vb" %> <%@ Import Namespace="System.Web.Caching" %> <script runat="server"> Const connectionString As String = "Server=localhost;Database=Pubs" Sub Page_Load() If Not IsPostBack Then SqlCacheDependencyAdmin.EnableNotifications( _ connectionString) SqlDataSource1.SelectParameters.Add("connectionString", _ connectionString) End If End Sub Sub EnableTable(ByVal s As Object, ByVal e As EventArgs) Try SqlCacheDependencyAdmin.EnableTableForNotifications( _ connectionString, txtTableName.Text) Catch ex As Exception lblErrorMessage.Text = ex.Message End Try txtTableName.Text = "" End Sub </script> <html> <head id="Head1" runat="server"> <title>ConfigureSCI</title> </head> <body> <form id="form1" runat="server"> <h1>SQL Cache Invalidation</h1>
以下表格已启用 SQL Cache Invalidation:
<p> <asp:GridView id="grdTables" DataSourceID="SqlDataSource1" CellPadding="10" ShowHeader="false" Runat="Server" /> </p> <asp:ObjectDataSource ID="SqlDataSource1" TypeName="System.Web.Caching.SqlCacheDependencyAdmin" SelectMethod="GetTablesEnabledForNotifications" Runat="Server" /> <p> <asp:Label ID="lblErrorMessage" EnableViewState="false" ForeColor="red" Runat="Server" /> </p> <asp:TextBox ID="txtTableName" Runat="Server" /> <asp:Button ID="Button1" Text="Enable Table" OnClick="EnableTable" Runat="Server" /> </form> </body> </html>
在列表 2 中,connectionString 常量用于选择启用了 SQL Cache Invalidation 的数据库(如果要为 Pubs 数据库以外的数据库启用 SQL Cache Invalidation,可以更改此常量的值)。在 Page_Load 方法中,调用 SqlCacheDependencyAdmin 类上的 EnableNotifications 方法,为由 connectionString 常量指定的数据库启用 SQL Cache Invalidation。
列表 2 中的 GridView 显示了当前启用了 SQL Cache Invalidation 的所有数据库表。GridView 被绑定到 ObjectDataSource 控件上,该控件为其 SelectMethod 调用 GetTablesneabledForNotifications 方法。
最后,您可以使用列表 2 中的页面为其他表启用 SQL Cache Invalidation。在文本框中输入表的名称并单击“Enable Table”按钮时,将调用 EnableTableForNotifications 方法。
SQL Cache Invalidation 的 Web 配置设置
在 ASP.NET 应用程序中使用 SQL Cache Invalidation 之前,下一步要做的是更新您的 Web 配置文件。您需要配置 ASP.NET Framework,以便轮询启用了 SQL Cache Invalidation 的数据库。
列表 3 中的 Web 配置文件包含轮询 Pubs 数据库所必需的配置信息。
列表 3:Web.Config
<configuration> <connectionStrings> <add name="mySqlServer" connectionString="Server=localhost;Database=Pubs" /> </connectionStrings> <system.web> <caching> <sqlCacheDependency enabled="true"> <databases> <add name="Pubs" connectionStringName="mySqlServer" pollTime="60000" /> </databases> </sqlCacheDependency> </caching> </system.web> </configuration>
列表 3 中的 Web 配置文件包含两部分。<connectionStrings> 部分用于创建数据库连接字符串,以连接到名为 mySqlServer 的 Pubs 数据库。
caching 部分用于配置 SQL Cache Invalidation 轮询。在 <databases> 子部分中,您可以列出要对其进行轮询以检查数据更改的一个或多个数据库。在列表 3 中,mySqlServer 表示的数据库每分钟(每 60000 毫秒)轮询一次。
您可以为不同的数据库指定不同的轮询间隔。每次轮询数据库以检查数据更改时,服务器都必须执行一些操作。如果您认为数据库中的数据不会频繁地更改,可以增加轮询间隔。
在页面输出缓存中使用 SQL Cache Invalidation
现在,我们已经完成了 SQL Cache Invalidation 的所有配置步骤,可以在 ASP.NET 页面中使用它了。一种方法是在页面输出缓存中使用 SQL Cache Invalidation。页面输出缓存允许您在内存中缓存页面所显示的所有内容。通过使用 SQL Cache Invalidation,您可以在(且只在)数据库表发生更改时自动更新缓存的页面。
例如,列表 4 中的页面在 GridView 控件中显示了 Titles 数据库表的内容。在该页面的顶部,OutputCache 指令用于在内存中缓存页面内容。如果 Titles 数据库表发生更改,SqlDependency 属性将使页面更新。
列表 4:OutputCacheTitles.aspx
<%@ OutputCache SqlDependency="Pubs:Titles" Duration="6000" VaryByParam="none" %> <html> <head runat="server"> <title>Output Cache Titles</title> </head> <body> <form id="form1" runat="server"> <%= DateTime.Now %> <asp:GridView ID="grdTitles" DataSourceID="SqlDataSource1" Runat="Server" /> <asp:SqlDataSource ID="SqlDataSource1" SelectCommand="Select * FROM Titles" ConnectionString="<%$ ConnectionStrings:mySqlServer %>" Runat="Server" /> </form> </body> </html>
请注意,SqlDependency 属性引用了 Web 配置文件中定义的数据库的名称。由于我们指定了每分钟轮询一次 Pubs 数据库以检查数据更改,因此如果对该数据库进行了更改,列表 4 中的页面将在一分钟之内进行更新。
您可以为 SqlDependency 属性值列出多个数据库和/或多个数据库表。要创建多个依赖关系,只需用分号分隔每个依赖关系即可。
在 DataSource 控件中使用 SQL Cache Invalidation
除了在页面输出缓存中使用 SQL Cache Invalidation 之外,还可以直接在 DataSource 控件中使用 SQL Cache Invalidation。如果要在多个页面中使用相同的数据库数据,请考虑在 DataSource 控件中使用 SQL Cache Invalidation。SqlDataSource、AccessDataSource 和 ObjectDataSource 控件都支持 SqlCacheDependency 属性。
例如,列表 5 中的页面在 SqlDataSource 控件中使用了 SQL Cache Invalidation。
列表 5:SqlDataSourceCaching.aspx
<html> <head id="Head1" runat="server"> <title>SqlDataSource Caching</title> </head> <body> <form id="form1" runat="server"> <%= DateTime.Now %> <asp:GridView ID="grdTitles" DataSourceId="SqlDataSource1" Runat="server" /> <asp:SqlDataSource ID="SqlDataSource1" EnableCaching="true" SqlCacheDependency="Pubs:Titles" SelectCommand="select * from titles" ConnectionString="<%$ ConnectionStrings:mySqlServer %>" Runat="server" /> </form> </body> </html>
在列表 5 中,SqlDataSource 控件是使用 EnableCaching 和 SqlCacheDependency 这两个属性声明的。SqlCacheDependency 属性使用的语法与 OutputCache 指令的 SqlDependency 属性相同。您需要列出数据库的名称,后跟数据库表的名称。
在 Cache 对象中使用 SQL Cache Invalidation
最后,您还可以在 Cache 对象中使用 SQL Cache Invalidation。此选项使您可以最大程度地对 SQL Cache Invalidation 进行编程控制。
要在 Cache 对象中使用 SQL Cache Invalidation,您需要创建一个 SqlCacheDependency 对象实例。使用 Insert 方法在 Cache 中插入新对象时,可以使用 SqlCacheDependency 对象。
例如,列表 6 中的页面显示了 Titles 数据库表中的记录数。计数是基于对基础数据库表的依赖关系进行缓存的。
列表 6:DisplayTitleCount.aspx (C#)
<%@ Page Language="c#" %> <%@ Import Namespace="System.Data.SqlClient" %> <script runat="server"> void Page_Load() { int count = 0; if (Cache["TitleCount"] != null) { count = (int)Cache["TitleCount"]; } else { string connectionString = ConfigurationSettings.ConnectionStrings[ "mySqlServer"].ConnectionString; SqlConnection con = new SqlConnection(connectionString); SqlCommand cmd = new SqlCommand("SELECT Count(*) FROM Titles", con); con.Open(); count = (int)cmd.ExecuteScalar(); con.Close(); Cache.Insert("TitleCount", count, new SqlCacheDependency("Pubs", "Titles")); } lblTitleCount.Text = count.ToString(); } </script> <html> <head runat="server"> <title>Display Title Count</title> </head> <body> <form id="form1" runat="server"> <asp:Label ID="lblTitleCount" Runat="Server" /> </form> </body> </html>
列表 6:DisplayTitleCount.aspx (Visual Basic .NET)
<%@ Page Language="vb" %> <%@ Import Namespace="System.Data.SqlClient" %> <script runat="server"> Sub Page_Load() Dim count As Integer = 0 If Not Cache("TitleCount") Is Nothing Then count = Convert.ToInt32(Cache("TitleCount")) Else Dim connectionString As String = _ ConfigurationSettings.ConnectionStrings( _ "mySqlServer").ConnectionString Dim con As New SqlConnection(connectionString) Dim cmd As New _ SqlCommand("SELECT Count(*) FROM Titles", con) con.Open() count = Convert.ToInt32(cmd.ExecuteScalar()) con.Close() Cache.Insert("TitleCount", count, _ new SqlCacheDependency("Pubs", "Titles")) End If lblTitleCount.Text = count.ToString() End Sub </script> <html> <head id="Head1" runat="server"> <title>Display Titles Count</title> </head> <body> <form id="form1" runat="server"> <asp:Label ID="lblTitleCount" Runat="Server" /> </form> </body> </html>
使用 Post-Cache Substitution
在许多情况下,您需要缓存页面的一部分,而不是整个页面。例如,在您的 Web 站点主页上,您可能希望同时显示随机的标题广告和数据库表中的记录。如果缓存整个页面,每个用户都将在每次请求的页面上看到同一个标题广告。
要处理这种同时混有动态内容和缓存内容的问题,一种方法是使用 Web 用户控件。因为可以为 Web 用户控件添加 OutputCache 指令,所以即使不缓存包含页面的内容,也可以缓存 Web 用户控件的内容。
但有时候可能会事与愿违。虽然您可以使用 Web 用户控件在动态页面上添加缓存的内容,但很多情况下,您实际上是想在缓存的页面中添加动态内容。例如,假设您要缓存整个页面的内容,只留一小块区域用于显示当前用户的用户名。这种情况下最好使用 Post-Cache Substitution。
ASP.NET 2.0 Framework 引入了一种新控件,称为 Substitution 控件。您可以使用 Substitution 控件在缓存的页面中插入动态内容。列表 7 中的页面使用 Substitution 控件将用户名插入到缓存的内容中(参见图 3)。
图 3:使用 Substitution 控件显示用户名
列表 7:PostCacheSubstitution.aspx (C#)
<%@ Page Language="C#" %> <%@ OutputCache Duration="6000" VaryByParam="none" %> <script runat="server"> static string DisplayUsername(HttpContext context) { if (!context.Request.IsAuthenticated) return "Anonymous"; else return context.User.Identity.Name; } </script> <html> <head runat="server"> <title>Post Cache Substitution</title> </head> <body> <form id="form1" runat="server"> Welcome <asp:Substitution MethodName="DisplayUsername" Runat="Server" />! <p> 此页已缓存, 因为时间 <%= DateTime.Now.ToString("t") %> 并无改变。 </p> </form> </body> </html>
列表 7:PostCacheSubstitution.aspx (Visual Basic .NET)
<%@ Page Language="vb" %> <%@ OutputCache Duration="6000" VaryByParam="none" %> <script runat="server"> Shared Function DisplayUsername(ByVal context As HttpContext) _ As String If Not context.Request.IsAuthenticated Then Return "Anonymous" Else Return context.User.Identity.Name End If End Function </script> <html> <head id="Head1" runat="server"> <title>Post Cache Substitution</title> </head> <body> <form id="form1" runat="server"> Welcome <asp:Substitution ID="Substitution1" MethodName="DisplayUsername" Runat="Server" />! <p> 此页已缓存, 因为时间 <%= DateTime.Now.ToString("t") %> 并无改变。 </p> </form> </body> </html>
Substitution 控件有一个非常重要的属性:即 MethodName 属性。MethodName 属性用于表示为返回动态内容而调用的方法。由 Substitution 控件调用的方法必须是静态方法(在 Visual Basic .NET 中共享的方法)。此外,该方法还必须具有一个表示当前 HttpContext 的参数。
在 ASP.NET 2.0 Framework 中,已对 AdRotator 控件进行了修改以支持 Post-Cache Substitution。如果在使用 OutputCache 指令的页面中添加 AdRotator 控件,AdRotator 控件将自动从其包含页面的缓存策略中排除出去。
结论
缓存对由数据库驱动的 Web 应用程序的性能具有非常大的影响。幸运的是,ASP.NET 2.0 Framework 提供了许多新的重要增强功能,使您可以在应用程序中更轻松地使用缓存功能。
新增的 DataSource 控件中包含的属性使得在内存中缓存数据库数据变得非常容易。通过使用 DataSource 控件,您可以检索并缓存数据库数据,而无需编写任何代码。
新增的 SQL Cache Invalidation 支持使您可以在基础数据库中的数据发生更改时自动在缓存中重新加载数据库数据。此功能为您提供了缓存的所有性能优势,而不用担心数据过期的问题。
最后,使用新增的 Substitution 控件,您可以更轻松地在缓存的页面中混合动态内容。Substitution 控件为您在缓存的页面中插入动态内容提供了一个独立的空间。
参考资料
• | |
• | |
• |
作者简介
Stephen Walther 编写了有关 ASP.NET 的畅销书 ASP.NET Unleashed。此外,他还是 ASP.NET Community Starter Kit(Microsoft 开发的 ASP.NET 示例应用程序)的体系结构设计师和主要开发人员。他还通过自己的公司 Superexpert (http://www.superexpert.com/) 为美国的公司(包括 NASA 和 Microsoft)提供 ASP.NET 培训。