页面缓存机制
页面输出缓存
页面输出缓存是最为简单的缓存机制,该机制将整个ASP.NET页面内容保存在服务器内存中。当用户请求该页面时,系统从内存中输出相关数据,直到缓存数据过期。在这个过程中,缓存内容直接发送给用户,而不必再次经过页面处理生命周期。通常情况下,页面输出缓存对于那些包含不需要经常修改内容的,但需要大量处理才能编译完成的页面特别有用。需要读者注意的是,页面输出缓存是将页面全部内容都保存在内存中,并用于完成客户端请求。
在ASP.NET中页面缓存的使用方法非常的简单,只需要在aspx页的顶部加这样一句声明即可:
<%@ OutputCacheDuration="60" VaryByParam="none" %>
事例:
后台代码
protected void Page_Load(object sender, EventArgse)
{
if (!IsPostBack)
{
Label1.Text = DateTime.Now.ToString();
}
}
protected voidButton1_Click(object sender, EventArgs e)
{
Label1.Text = DateTime.Now.ToString();
}
说明:页面每60秒变更一次时间
VaryByParam
是指页面根据使用 POST 或 GET 发送的名称/值对(参数)来更新缓存的内容,多个参数用分号隔开。如果不希望根据任何参数来改变缓存内容,请将值设置为 none。如果希望通过所有的参数值改变都更新缓存,请将属性设置为星号 (*)。
事例:
<%@ OutputCacheDuration="60" VaryByParam="id" %>
如:http://localhost:1165/16-4-3/WebForm1.aspx?id=1
只有在id变更或同一id号到60秒时,页面才会刷新
CacheProfile
用于调用Web.config配置文件中设置的缓存时间。这是可选属性,默认值为空字符 ("")。
例如:
在Web.config中加入配置:
<caching>
<outputCacheSettings>
<outputCacheProfiles>
<addname="CacheTest"duration="60" />
</outputCacheProfiles>
</outputCacheSettings>
</caching>
前台加入:<%@ OutputCache CacheProfile="CacheTest"VaryByParam="id" %>
页面局部缓存
1. 控件缓存(也称为片段缓存)
这种方式允许将需要缓存的信息包含在一个用户控件内,然后,将该用户控件标记为可缓存的,以此来缓存页面输出的部分内容。该选项允许缓存页面中的特定内容,而没有缓存整个页面,因此,每次都需重新创建整个页。例如,如果要创建一个显示大量动态内容(如股票信息)的页,其中有些部分为静态内容(如每周总结),这时可以将静态部分放在用户控件中,并允许缓存这些内容。
在ASP.NET中,提供了UserControl这种用户控件的功能。一个页面可以通过多个UserControl来组成。只需要在某个或某几个UserControl里设置缓存。
例如:
那么可以在WebUserControl1.ascx的页头代码中添加声明语句:
<%@ OutputCacheDuration="60"VaryByParam="none"%>
<%=DateTime.Now %>
调用该控件的页面WebForm1.aspx代码:
控件的:<uc1:WebUserControl1 ID="WebUserControl11" runat="server" /><br />
页面的:<%=DateTime.Now %>
2. 缓存后替换
与控件缓存正好相反。它对整个页面进行缓存,但是页中的某些片段是动态的,因此不会缓存这些片段。ASP.NET页面中既包含静态内容,又包含基于数据库数据的动态内容。静态内容通常不会发生变化。因此,对静态内容实现数据缓存是非常必要的。然而,那些基于数据的动态内容,则不同。数据库中的数据可能每时每刻都发生变化,因此,如果对动态内容也实现缓存,可能造成数据不能及时更新的问题。对此问题如果使用前文所述的控件缓存方法,显然不切实际,而且实现起来很繁琐,易于发生错误。
(1) Substitution控件应用
为提高应用程序性能,可能会缓存整个ASP.NET页面,同时,可能需要根据每个请求来更新页面上特定的部分。例如,可能要缓存页面的很大一部分,需要动态更新该页上与时间或者用户高度相关的信息。在这种情况下,推荐使用Substitution控件。Substitution控件能够指定页面输出缓存中需要以动态内容替换该控件的部分,即允许对整页面进行输出缓存,然后,使用Substitution控件指定页中免于缓存的部分。需要缓存的区域只执行一次,然后从缓存读取,直至该缓存项到期或被清除。动态区域,也就是Substitution控件指定的部分,在每次请求页面时都执行。Substitution控件提供了一种缓存部分页面的简化解决方案。
<%@ OutputCacheDuration="50"VaryByParam="none"%>
页面缓存的时间:<%= DateTime.Now.ToString()%>
真实(替换)的时间: <asp:Substitution ID="Substitution1" runat="server" MethodName="getCurrentTime" />
后台代码:
public static string getCurrentTime(HttpContextcontext)
{
return DateTime.Now.ToString();
}
如上代码所示,Substitution控件有一个重要属性:MethodName。该属性用于获取或者设置当Substitution控件执行时为回调而调用的方法名称。该方法比较特殊,必须符合以下3条标准:
· 此方法必须被定义为静态方法;
· 此方法必须接受HttpContext类型的参数;
· 此方法必须返回String类型的值。
· 在运行情况下,Substitution控件将自动调用MethodName属性所定义的方法。该方法返回的字符串即为要在页面中的Substitution控件的位置上显示的内容。如果页面设置了缓存全部输出,那么在第一次请求时,该页将运行并缓存其输出。对于后续的请求,将通过缓存来完成,该页上的其他代码不会再运行。但Substitution控件及其有关方法则在每次请求时都执行,并且自动更新该控件所表示的动态内容,这样就实现了整体缓存,局部变化的替换效果。
·
· 如上代码所示,在代码头部通过@OutputCache指令设置页面输出缓存过期时间为5秒,这意味着整个页面数据都应用了缓存功能。因此,“页面缓存的时间”所显示的时间值来自于数据缓存。这个时间值不会随着刷新页面而变化,仅当缓存过期时才会发生更新。Substitution控件的MethodName属性值为getCurrentTime。该控件显示的内容来自于getCurrentTime方法的返回值。尤为重要的是,虽然页面设置了输出缓存功能,但是每当页面刷新时,ASP.NET执行引擎仍然要重新执行Substitution控件,并将MethodName属性值指定的方法返回值显示在页面上,因此,显示的是当前最新时间。
(2) Substitution控件API应用
上一小节介绍了以声明方式使用Substitution控件实现缓存后替换的应用。本节说明另一种实现方法。该方法的核心是以编程方式利用Substitution控件API实现缓存后替换,相对于以声明方式使用Substitution控件的方法具有更强灵活性。
通过为Substitution指定回调方法,实现和声明同样的效果。Substitution的回调方法必须是
HttpResponseSubstitutionCallback委托定义的方法,它有两个特征:
l 一是返回值必须是String,
l 二是参数有且仅有一个,并且是HttpContext类型。
当需要以编程方式,为缓存的输出响应动态生成指定的响应区域时,可以在页面代码中将某个方法(即回调方法)的名称作为参数(HttpResponseSubstitutionCallback)传递给Substitution。这样Substitution就能够使用回调方法,并将回调方法的返回值作为给定位置的替代内容显示出来。
需要注意的是,回调方法必须是线程安全的,可以是作为容器的页面或者用户控件中的静态方法,也可以是其他任意对象上的静态方法或实例方法。
下面演示一个以编程方式将 Substitution 控件添加到输出缓存网页。与(1)Substitution控件应用所示的示例完成同样功能。不同的是实现方式。
<%@ OutputCacheDuration="50"VaryByParam="none"%>
页面缓存的时间:<%= DateTime.Now.ToString()%> <br />
真实(替换)的时间:
<asp:PlaceHolder ID="PlaceHolder1"runat="Server"></asp:PlaceHolder>
后台:
protected void Page_Load(object sender, EventArgse)
{
if (!IsPostBack)
{
Substitution sub1 = new Substitution();
sub1.MethodName = "getCurrentTime";
PlaceHolder1.Controls.Add(sub1);
}
}
public static string getCurrentTime(HttpContextcontext)
{
return DateTime.Now.ToString();
}
系统缓存全解析4:应用程序数据缓存
System.Web.Caching 命名空间提供用于缓存服务器上常用数据的类。此命名空间包括 Cache 类,该类是一个字典,您可以在其中存储任意数据对象,如哈希表和数据集。它还为这些对象提供了失效功能,并为您提供了添加和移除这些对象的方法。您还可以添加依赖于其他文件或缓存项的对象,并在从 Cache 对象中移除对象时执行回调以通知应用程序。
protected void Page_Load(object sender, EventArgse)
{
if (!IsPostBack)
{
string CacheKey = "cachetest";
object objModel = GetCache(CacheKey);
if (objModel == null)
{
objModel = DateTime.Now;
}
if (objModel != null)
{
int CacheTime = 30;
SetCache(CacheKey, objModel, DateTime.Now.AddSeconds(CacheTime),TimeSpan.Zero);
}
Label1.Text = objModel.ToString();
}
}
public static object GetCache(stringCacheKey)
{
System.Web.Caching.Cache objCache=HttpRuntime.Cache;
return objCache[CacheKey];
}
public static void SetCache(stringCacheKey,object objObject)
{
Cache objcache=HttpRuntime.Cache;
objcache.Insert(CacheKey,objObject);
}
public static void SetCache(stringCacheKey, object objObject, DateTime absoluteExpiration, TimeSpan slidingExpiration)
{
System.Web.Caching.Cache objCache = HttpRuntime.Cache;
objCache.Insert(CacheKey, objObject, null,absoluteExpiration, slidingExpiration);
}
}
以上几种方法都很好的解决了数据缓存的问题,但由一个最大的问题是当数据发生变化了,而缓存里还是过期的数据,只有等缓存过期后才会重新获取最新的数据,这样的话,很多时候用户获取的数据都是和实际数据不一致的过期数据。这同样给用户造成了比较大的麻烦,怎么办呢?接着往下看。
===============================================================================
系统缓存全解析5:文件缓存依赖
这种策略让缓存依赖于一个指定的文件,通过改变文件的更新日期来清除缓存。
public static object GetCache(stringCacheKey)
{
System.Web.Caching.Cache objCache = HttpRuntime.Cache;
return objCache[CacheKey];
}
///<summary>
///设置以缓存依赖的方式缓存数据
///</summary>
///<param name="CacheKey">索引键值</param>
///<param name="objObject">缓存对象</param>
///<param name="cacheDepen">依赖对象</param>
public static void SetCache(stringCacheKey, object objObject, System.Web.Caching.CacheDependency dep)
{
System.Web.Caching.Cache objCache = HttpRuntime.Cache;
objCache.Insert(
CacheKey,
objObject,
dep,
System.Web.Caching.Cache.NoAbsoluteExpiration,//从不过期
System.Web.Caching.Cache.NoSlidingExpiration,//禁用可调过期
System.Web.Caching.CacheItemPriority.Default,
null);
}
protected voidPage_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
string CacheKey = "cachetest";
object objModel = GetCache(CacheKey);//从缓存中获取
if (objModel == null)//缓存里没有
{
objModel = DateTime.Now;//把当前时间进行缓存
if (objModel != null)
{
//依赖 C:\\test.txt 文件的变化来更新缓存
System.Web.Caching.CacheDependency dep = newSystem.Web.Caching.CacheDependency("I:\\test.txt");
SetCache(CacheKey,objModel, dep);//写入缓存
}
}
Label1.Text = objModel.ToString();
}
}
}