第11章 ASP.NET缓存机制
本章视频教学录像:18分钟
缓存是系统或应用程序将频繁使用的数据保存到内存中,当系统或应用程序再次使用时,能够快速地获取数据。缓存技术是提高Web应用程序开发效率的最常用的技术。在ASP.NET中,有三种Web应用程序可以使用缓存技术,即页面输出缓存、页面部分缓存和页面数据缓存,本章将分别介绍这三种缓存技术。
本章要点(已掌握的在方框中打钩)
□ 了解ASP.NET缓存
□ 页面输出缓存
□ 页面部分缓存
□ 页面数据缓存
11.1 ASP.NET缓存概述
本节视频教学录像:3分钟
缓存是ASP.NET中非常重要的一个特性,可以生成高效能的Web应用程序。生成高效能的Web应用程序最重要的因素之一,就是将那些频繁访问、而且不需要经常更新的数据存储在内存中,当客户端再一次访问这些数据时,可以避免重复获取满足先前请求的信息,实现快速显示请求的Web页面。
ASP.NET 4.0中有3种Web应用程序可以使用缓存技术,即页面输出缓存、页面部分缓存和页面数据缓存。ASP.NET 4.0的缓存功能具有以下优点:
1. 支持更为广泛和灵活的可开发特性
ASP.NET4.0包含一些新增的缓存控件和API。例如,自定义缓存依赖、Substitution控件、页面输出缓存API等,这些特征能够明显改善开发人员对于缓存功能的控制。
2. 增强可管理性
使用ASP.NET4.0提供的配置和管理功能,可以更加轻松地管理缓存功能。
3. 提供更高的性能和可伸缩性
ASP.NET4.0提供了一些新的功能,例如SQL数据缓存依赖等,这些功能帮助开发人员创建高性能、伸缩性强的Web应用程序。
当然除此之外,缓存功能也有自身的不足,比如显示的内容可能不是最新、最准确的,为此必须设置合适的缓存策略。又如,缓存增加了系统的复杂性并使其难于测试和调试,因此建议在没有缓存的情况下开发和测试应用程序,然后在性能优化阶段启用缓存选项。
如果不设置缓存,ASP.NET会根据每个请求重复n次,这就增加了不必要的开销。所以,可能的情况下尽量使用缓存,从内存中返回数据的速度始终比去数据库查的速度快,因而可以大大提高应用程序的性能。毕竟现在内存非常便宜,用空间换取时间效率应该是非常划算的。尤其是对耗时比较长的、需要建立网络连接的数据库查询操作等。
11.2 页面缓存
本节视频教学录像:11分钟
本节介绍页面缓存的相关内容。
11.2.1 页面输出缓存
页面输出缓存是最为简单的缓存机制,该机制将整个ASP.NET页面内容保存在服务器内存中。当用户请求该页面时,系统从内存中输出相关数据,直到缓存数据过期。在这个过程中,缓存内容直接发送给用户,而不必再次经过页面处理生命周期。通常情况下,页面输出缓存对于那些包含不需要经常修改内容的,但需要大量处理才能编译完成的页面特别有用。需要读者注意的是,页面输出缓存是将页面全部内容都保存在内存中,并用于完成客户端请求。
页面输出缓存需要利用有效期来对缓存区中的页面进行管理。设置缓存的有效期可以使用@OutputCache指令。@OutputCache指令如下:
<% @ OutputCache Duration="#ofseconds"
Location="Any | Client | Downstream | Server | None | ServerAndClient "
Shared="True | False"
VaryByControl="controlname"
VaryByCustom="browser | customstring"
VaryByHeader="headers"
VaryByParam="parametername"
%>
@OutputCache指令中的各个属性的说明如下:
⑴Duration:页或用户控件进行缓存的时间(以秒计)。在页或用户控件上设置该属性为来自对象的 HTTP 响应建立了一个过期策略,并将自动缓存页或用户控件输出。该属性是必须的。
⑵Location:用于指定输出缓存项的位置。其属性值是OutputCacheLocation枚举值,它们是Any、Client、Downstream、None、Server和ServerAndClient。默认值是Any,表示输出缓存可用于所有请求,包括客户端浏览器、代理服务器或处理请求的服务器上。需要注意的是,包含在用户控件中的@ OutputCache指令不支持此属性。
⑶Shared:一个布尔值,确定用户控件输出是否可以由多个页共享。默认值为False。
⑷VaryByControl:该属性使用一个分号分隔的字符串列表来更改用户控件的输出缓存。这些字符串代表在用户控件中声明的ASP.NET服务器控件的ID属性值。除非已经包含了VaryByParam属性,否则在@ OutputCache指令中,该属性是必需的。
⑸VaryByCustom:用于自定义输出缓存要求的任意文本。如果赋予该属性值是browser,缓存将随浏览器名称和主要版本信息的不同而异。如果输入了自定义字符串,则必须在应用程序的Global. asax文件中重写HttpApplication.GetVaryByCustomString方法。
⑹VaryByHeader:该属性中包含由分号分隔的HTTP标头列表,用于使输出缓存发生变化。当将该属性设为多标头时,对于每个指定的标头,输出缓存都包含一个请求文档的不同版本。VaryByHeader属性在所有HTTP 1.1缓存中启用缓存项,而不仅限于ASP.NET缓存。
⑺VaryByParam:该属性定义了一个分号分隔的字符串列表,用于使输出缓存发生变化。默认情况下,这些字符串与用GET方法属性发送的查询字符串值对应,或与用POST方法发送的参数对应。当将该属性设置为多参数时,对于每个指定的参数,输出缓存都包含一个请求文档的不同版本。可能的值包括“none”、“*”和任何有效的查询字符串或POST参数名称。
【范例11-1】设置页面缓存的过期时间为当前时间加上60秒。
程序实现的主要步骤如下:
⑴新建ASP.NET空网站PageOutputCache,添加页面并采用默认名称。
⑵将Default.aspx页面切换到HTML视图中,在<%@ Page%>指令的下方添加如下代码,实现页面缓存的过期时间为当前的时间加上60秒:
<% @ OutputCache Duration ="60" VaryByParam ="none"%>
⑶双击页面打开Default.aspx.cs页面,添加如下代码,输出当前的系统时间,用于比较程序在60秒内和60秒后的运行状态。
01 void Page_Load(object sender,EventArgs e)
02 {
03 Response.Write("页面缓存设置示例:<br>设置缓存时间为60秒,当前时间为:" + DateTime.Now.ToString());
04 }
【运行结果】
按【Ctrl+F5】组合键运行,测试运行结果,如图所示。程序运行60秒内刷新页面,页面中的数据不发生变化;60秒后刷新页面,页面中的数据发生变化。
11.2.2 页面局部缓存
本节介绍页面局部缓存的相关内容。
1. 页面输出缓存概述
通常情况下,缓存整个页面是不合理的,因为页的某些部分在每一次请求都进行更改,这种情况下,只能缓存页的一部分即页面部分缓存。页面部分缓存是将页面的部分内容保存在内存中以便响应用户请求,而页面其他部分内容则为动态内容。页面部分缓存的信息包含在一个用户控件内,然后将该用户控件标记为可缓存的,以此来缓存页面输出的部分内容。片段缓存,也就是控件缓存,这一方式缓存了页面的特定内容,而没有缓存整个页面,因此,每次都需要重新创建整个页。而另外一种方式,替换后缓存与用户控件缓存正好相反。这种方式缓存整个页,但页中的各段都是动态的。
设置控件缓存的实质是对用户控件进行缓存配置。主要包括以下3种方法。
⑴使用@ OutputCache指令以声明方式为用户控件设置缓存功能。
⑵在代码隐藏文件中使用PartialCachingAttribute类设置用户控件缓存。
⑶使用ControlCachePolicy类以编程方式指定用户控件缓存设置。
2. 使用@ OutputCache指令设置用户控件缓存功能
@ OutputCache指令以声明方式为用户控件设置缓存功能,用户控件缓存与页面输出缓存的@ OutputCache指令设置方法基本相同,都在文件顶部设置@ OutputCache指令。不同点包括如下两个方面。
⑴用户控件缓存功能的 @ OutputCache 指令设置在用户控件文件内,而页面输出缓存的@ OutputCache指令设置在普通ASP.NET文件中。
⑵用户控件缓存的@ OutputCache指令只能设置6个属性,即Duration、Shared、SqlDependency、VaryByControl、VaryByCustom和VaryByParam。而在页面缓存的@ OutputCache指令字符串设置的属性多达10个。
用户控件中的@ OutputCache指令设置源代码如下:
<% @ OutputCache Duration ="60" VaryByParam ="none" VaryByControl =“ControlID”%>
以上代码为用户控件中的服务器控件设置缓存,其中缓存时间为60秒,ControlID是服务器控件ID属性值。
3. 使用PartialCachingAttribute类设置用户控件缓存功能
使用PartialCachingAttribute类可以在用户控件(.ascx文件)中设置有关控件缓存的配置内容。PartialCachingAttribute类包含六个常用属性和四个类构造函数,其中六个常用属性与@OutputCache指令设置的六个属性完全相同,只是使用方式不同,这里不再赘述。下面重点介绍PartialCachingAttribute类中的构造函数,PartialCachingAttribute类的四种构造函数如下:
⑴[PartialCaching(int duration)]。
这是最为常用的一种格式。其参数duration为整数类型,用于设置用户控件缓存有效期时间值。该参数与@ OutputCache指令中的Duration属性对应。
⑵[PartialCaching(int duration, string varyByParams, string varyByControls, string varyByCustom)]。
这种格式设置的内容较多。参数duration与上面说明的相同。参数varyByParams是一个由分号分隔的字符串列表,用于使输出缓存发生变化。该参数与@OutputCache指令中的VaryByParam属性对应。参数varyByControls是一个由分号分隔的字符串列表,用于使输出缓存发生变化,其与@OutputCache指令中的VaryByControl属性对应。参数varyByCustom用于设置任何表示自定义输出缓存要求的文本,与@OutputCache指令中的VaryByCustom属性对应。
⑶[PartialCaching(int duration, string varyByParams, string varyByControls, string varyByCustom, bool shared)]。
这种格式中,参数duration、varyByParams、varyByControls、varyByCustom都与上面说明的参数相同。只有参数shared是新添加的。参数shared值是一个布尔值,用于确定用户控件输出缓存是否可以由多个页面共享。默认值为false。当该参数设置为true,表示用户控件输出缓存可以被多个页面共享,可以潜在节省大量内存。
⑷[PartialCaching(int duration, string varyByParams, string varyByControls, string varyByCustom, string sqlDependency, bool shared)]。
以上格式中添加了一个新参数sqlDependency。用于设置用户控件缓存入口所使用SQL Server缓存依赖功能的数据库及表名。如果包含多个数据库及表名,则使用分号(;)分隔开来。当该属性值发生变化时,缓存入口将过期。另外,数据库名必须与web.config文件中的<sqlcachedependency>配置节的内容匹配。
以上介绍了PartialCachingAttribute类的六个属性和四种构造函数。下面通过一个典型示例说明该类的具体应用方法。
【范例11-2】使用PartialCachingAttribute类实现设置用户控件缓存。
⑴新建ASP.NET空网站命名为PartialCachingAttribute,添加默认主页Default.aspx,并在该页中添加一个Label控件用于显示当前系统时间。因此在Default.aspx.cs的Page_Load()事件中输入以下代码:
01 protected void Page_Load(object sender, EventArgs e)
02 {
03 this.Label1.Text= "Web页中的系统时间:"+DateTime.Now.ToString();
04 }
⑵在项目名称上点击右键,选择【添加新项】【web用户控件】,默认名为WebUserControl.ascx,并在该用户控件中添加一个Label控件用于显示当前的系统时间。
⑶为了使用PartialCachingAttribute类设置用户控件(WebUserControl.ascx文件)的缓存有效期为20秒,必须在用户控件类声明前设置“[PartialCaching(20)]”。代码如下:
01 [PartialCaching(20)]
02 public partial class _Default :System.Web.UI.Page
03 {
04 protected void Page_Load(object sender,EventArgs e)
05 {
06 this.Label1.Text= "用户控件中的系统时间:"+DateTime.Now.ToString();
07 }
08 }
【运行结果】
按【Ctrl+F5】组合键运行,示例运行结果如图所示,示例运行20秒内刷新,运行结果中用户控件中的系统时间不变,但是Web页中的系统时间仍然变化;运行20秒后刷新页面,用户控件和Web页中的系统时间都会发生变化。
4. 使用ControlCachePolicy
ControlCachePolicy是.NET Framework 2.0中新增的类,主要用于提供对用户控件的输出缓存设置的编程访问。ControlCachePolicy类包含6个属性,分别是Cached、Dependency、Duration、SupportsCaching、VaryByControl和VaryByParams。
⑴Cached:用于获取或者设置一个布尔值,表示是否在用户控件中启用控件缓存功能。true表示启用控件缓存功能,否则为false。
⑵Dependency:用于获取或者设置一个CacheDependency实例对象,该对象与用户控件的输出缓存关联。默认值为null。当CacheDependency实例对象失效时,用户控件的输出缓存将从缓存中移除。
⑶Duration:获取或者设置一个TimeSpan结构,表示用户控件输出缓存的有效时间。默认值为Zero。
⑷SupportsCaching:该属性获取一个布尔值,用于表示用户控件是否支持缓存功能。如果属性值为true,则表示该用户控件支持缓存;否则为false。
⑸VaryByControl:用于获取或者设置一个由分号分隔的字符串列表,这些字符串包含在用户控件中声明的服务器控件ID属性值。用户控件可根据该属性值,使输出缓存发生变化。
⑹VaryByParams:用于获取或者设置一个由分号分隔的字符串列表。默认情况下,这些字符串与用GET方法属性发送的查询字符串值对应,或与用POST方法发送的参数对应。用户控件可根据该属性值,使输出缓存发生变化。
下面通过一个例子说明该类的具体应用方法。
【范例11-3】使用ControlCachePolicy类实现设置用户控件缓存。
下面的示例主要演示如何在运行时动态加载用户控件,如何以编程方式设置用户控件缓存过期时间为20秒,以及如何使用绝对过期策略。
程序实现的主要步骤为:
⑴新建ASP.NET空网站并命名为PartialCachingAttribute,添加默认主页Default.aspx,并在该页中添加一个Label控件用于显示当前系统时间。
⑵在项目名称上单击右键,选中【添加新项】【web用户控件】命令,默认名为WebUserControl.ascx,并在该用户控件中添加一个Label控件用于显示当前的系统时间。
⑶使用PartialCachingAttribute类设置用户控件(WebUserControl.ascx文件)的默认缓存有效期为80秒。代码如下:
01 [PartialCaching(80)]
02 public partial class WebUserControl :System.Web.UI.UserControl
03 {
04 protected void Page_Load(object sender,EventArgs e)
05 {
06 Label1.Text= "用户控件中的系统时间:"+DateTime.Now.ToLongTimeString();
07 }
08 }
⑷在 Default.aspx 页面中的 Page_Init 事件下动态加载用户,并使用 SetSlidingExpitation 和SetExpires方法更改用户控件的缓存过期时间为20秒,Page_Init事件的代码如下:
01 protected void Page_Init(Object sender,EventArgs e)
02 {
03 this.Label1.Text= "Web页中的系统时间:"+DateTime.Now.ToLongTimeString();
04 PartialCachingControlpcc= LoadControl("WebUserControl.ascx") asPartialCachingControl;
05 if (pcc.CachePolicy.Duration> TimeSpan.FromSeconds(60))
06 {
07 pcc.CachePolicy.SetExpires(DateTime.Now.Add(TimeSpan.FromSeconds(20)));
08 pcc.CachePolicy.SetSlidingExpiration(false);
09 }
10 Controls.Add(pcc);
11 }
【运行结果】
按【Ctrl+F5】组合键运行,执行程序。示例运行结果如图所示,示例运行10秒后刷新页面,运行结果中用户控件中的系统时间不变,但是Web页中的系统时间仍然变化;运行20秒后刷新页面,用户控件和Web页中的系统时间都会发生变化。读者会发现整个过程中中间的用户控件中的系统时间保持不变,这是因为这个缓存有效期是由初次加载时的默认缓存有效期决定的,而初次加载时默认缓存有效期大于20秒,因此,20秒内这个时间是不会有变化的。
示例运行初期:
12秒后刷新:
20秒后刷新:
11.2.3 页面数据缓存
页面数据缓存即应用程序数据缓存,它提供了一种编程方式,可通过键/值将任意数据存储在内存中。使用应用程序缓存与使用应用程序状态类似,但是与应用程序状态不同的是,应用程序数据缓存中的数据是容易丢失的,即数据并不是在整个应用程序生命周期中都存储在内存中。应用程序数据缓存的优点是由ASP.NET管理缓存,它会在项过期、无效或内存不足时移除缓存中的项,还可以配置应用程序缓存,以便在移除项时通知应用程序。
ASP.NET中提供了类似于Session的缓存机制,即页面数据缓存。利用页面数据缓存,可以在内存中存储各种与应用程序相关的对象。对于各个应用程序来说,数据缓存只是在应用程序内共享,并不能在应用程序间共享。Cache类用于实现Web应用程序的缓存,在Cache中存储数据最简单的方法如下:
Cache[“Key”] = Value;
从缓存中取数据时,需要先判断一下缓存中是否有内容,另外需要注意的是从Cache中取出的是一个Object类型的对象,注意类型转换,其方法如下:
Value = (String)Cache[“key”];
If(Value != null)
{
//do something;
}
Cache类中有两个重要的方法,即Add和Insert方法,其语法格式如下:
public Object Add[Insert](
string key,
Object value,
CacheDependency dependencies,
DateTime absoluteExpiration,
TimeSpan slidingExpiration,
CacheItemPriority priority,
CacheItemRemovedCallback onRemoveCallback
)
参数说明:
⑴key
类型:SystemString
用于引用该项的缓存键。
⑵value
类型:SystemObject
要添加到缓存的项。
⑶dependencies
类型:System.Web.CachingCacheDependency
该项的文件依赖项或缓存键依赖项。当任何依赖项更改时,该对象即无效,并从缓存中移除。如果没有依赖项,则此参数可以设置为null 。
⑷absoluteExpiration
类型:SystemDateTime
所添加对象将到期并被从缓存中移除的时间。如果使用可调到期,则 absoluteExpiration 参数必须为NoAbsoluteExpiration。
⑸slidingExpiration
类型:SystemTimeSpan
最后一次访问所添加对象时与该对象到期时之间的时间间隔。如果该值等效于20分钟,则对象在最后一次被访问20分钟之后将到期并从缓存中移除。如果使用绝对到期,则slidingExpiration参数必须为NoSlidingExpiration。
⑹priority
类型:System.Web.CachingCacheItemPriority
对象的相对成本,由CacheItemPriority枚举表示。缓存在退出对象时使用该值;具有较低成本的对象在具有较高成本的对象之前被从缓存中移除。
⑺onRemoveCallback
类型:System.Web.CachingCacheItemRemovedCallback
在从缓存中移除对象时所调用的委托(如果提供)。当从缓存中删除应用程序的对象时,可使用它来通知应用程序。
Insert方法声明与Add方法类似,但Insert方法为可重载方法,其结构如表所示。
在Insert方法中,CacheDependency是指依赖关系,DateTime是指有效时间,TimeSpan是创建对象的时间间隔。
下面通过几个小示例,来讲解Insert方法的使用。
例如:将文件中的XML数据插入缓存,无需在以后请求时从文件中读取。CacheDependency的作用是确保缓存在文件更改后立即到期,以便可以从文件中提取最新数据,重新进行缓存。如果缓存的数据来自若干个文件,还可以指定一个文件名的数组。代码如下:
Cache.Insert(“key”, myXMLFileData, new System.Web.Caching.CacheDependency
(Server.MapPath(“user.xml”)));
例如:插入键值为key的第二个数据块(取决于是否存在第一个数据块)。如果缓存中不存在名为key的键,或者与该键相关联的项已到期或被更新,那么dependentkey的缓存条目将到期,代码如下:
Cache.Insert(“dependenctkey”, myDependentData, new
System.Web.Caching.CacheDependency(new String[]{}, new Stirng[] {“key”}));
下面是一个绝对到期的示例,此示例将对受时间影响的数据缓存1分钟,1分钟过后,缓存将到期。其中有一点需要注意,绝对到期和滑动到期不能一起使用。
Cache.Insert(“key”, myTimeSensitiveData, null,
DateTime.Now.AddMinutes(1), TimeSpan.Zero);
下面是一个滑动到期的示例,此示例将缓存一些频繁使用的数据。数据将在缓存中一直保存下去,除非数据未被引用的时间达到了1分钟。
Cache.Insert(“key”, myFrequentlyAccessedData, null,
System.Web.Caching.Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(1));
11.3 高手点拨
本节视频教学录像:4分钟
1. 通过Response.Cache以编程的方式设置网页输出缓存时间
设置网页输出缓存的持续时间,可以采用编程的方式通过Response.Cache方法来实现。其使用方法如下:
Response.Cache.SetExpires(DateTime.Now.AddMinutes(20)); //20秒后移除
Response.Cache.SetExpires(DateTime.Parse(“4:00:00PM”)); //有效期到下午4点
Response.Cache.SetMaxAge(new TimeSpan(0,0,10,0)); //有效期为10分钟
2. 设置网页缓存的位置
网页缓存的位置可以根据缓存的内容来决定,比如,对于安全性要求比较高的网页,最好在Web服务器上进行缓存;对于普通网页,则可以允许在任何具有缓存功能的装置上缓存,以提高资源的使用率。
如果使用@OutputCache指令进行网页输出缓存位置的设置,可以使用Location属性。例如,设置网页只能缓存在服务器的代码如下:
<%@OutputCache Duration=”60”VaryByParam=”none”Location=”Server”%>
11.4 实战练习
1. 创建ASP.NET网站,并设置页面缓存的过期时间为当前时间加上60秒。
2. 使用11.2.2小节中提供的任意一种方法设置用户控件缓存功能,并查看用户系统时间和Web页中的系统时间对比,理解缓存的概念和实现。