ASP.NET 缓存

缓存的分类

客户端缓存:主要与客户端的浏览器缓存有关系!

 

服务器端缓存:服务器端缓存从性质上看,又可以分为两种。

 

静态文件缓存:好多页面是静态的,很少改动,那么这种文件最适于作静态缓存。现在的IIS 6.0这部分内容是直接存放在Kernel的内存中,由HTTP.SYS直接管理。由于它在Kernel Space,所以它的性能非常的高。用户的请求如果在缓存里面,那么HTTP.SYS直接将内容发送到network driver上去,不需要像以前那样从IISUser space的内存copyKernel中,然后再发送到TCP/IP stack上。Kernel level cache几乎是现在高性能Web server的一个必不可少的特性。

 

动态缓存:动态缓存是比较有难度的。因为你在缓存的时候要时刻注意一个问题,那就是缓存的内容是不是已经过时了。因为内容过时了可能会有很严重的后果。

 

ASP.NET中,常见的动态缓存主要有:

·    页面输出缓存

·    页面局部缓存

·    System.Web.Caching

·    缓存依赖

 

传统缓存方式

比如将可重复利用的东西放到Application或是Session中去保存。

Session["Style"] = val;

Application["Count"] = 0;

 

页面输出缓存

页面输出缓存是最为简单的缓存机制,该机制将整个ASP.NET页面内容保存在服务器内存中。当用户请求该页面时,系统从内存中输出相关数据,直到缓存数据过期。在这个过程中,缓存内容直接发送给用户,而不必再次经过页面处理生命周期。通常情况下,页面输出缓存对于那些不经常修改内容的,但需要大量处理才能编译完成的页面特别有用。需要读者注意的是,页面输出缓存是将页面全部内容都保存在内存中,并用于完成客户端请求。

 

方法: <%@ OutputCache Duration="60" VaryByParam="none" %>

Duration:缓存的时间(秒)。这是必选属性。如果未包含该属性,将出现分析器错误。

 

例子:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="CacheWebApp._16_4_3.WebForm1" %>

<%@ OutputCache Duration="60" VaryByParam="none" %>

<html xmlns="http://www.w3.org/1999/xhtml" >

<head runat="server">

    <title>页面缓存示例</title>

</head>

<body>

    <form id="form1" runat="server">

    <div>

        <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>

    </div>

    </form>

</body>

</html>

 

后台代码:

       protected void Page_Load(object sender, EventArgs e)

        {

            if (!IsPostBack)

            {

                Label1.Text = DateTime.Now.ToString();

            }

        }

        

注:没有缓存前每次刷新页面上的时间每次都在变。而加了缓存声明以后,每次刷新页面的时间并不变化,60秒后才变化一次,说明数据被缓存了60秒。

 

VaryByParam

是指页面根据使用 POST GET 发送的名称/值对(参数)来更新缓存的内容,多个参数用分号隔开。如果不希望根据任何参数来改变缓存内容,请将值设置为 none。如果希望通过所有的参数值改变都更新缓存,请将属性设置为星号 (*)

 

例如: http://localhost:1165/16-4-3/WebForm1.aspx?p=1

则可以在WebForm1.aspx页面头部声明缓存:<%@ OutputCache Duration="60" VaryByParam="p" %>,设置页面缓存时间是60秒,并根据p参数的值来更新缓存,即p的值发生变化才更新缓存。

 

如果一直是WebForm1.aspx?p=1访问该页,则页面会缓存当前数据,当p=2时又会执行后台代码更新缓存内容。 另外注意每一个缓存变量值都是独立的!

 

如果有多个参数时,如:http://localhost:1165/16-4-3/WebForm1.aspx?p=1&n=1,声明为:<%@ OutputCache Duration="60" VaryByParam="p;n" %> 

 

@OutputCache 还有其他的属性:

<%@ 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"

%>

 

CacheProfile用于调用Web.config配置文件中设置的缓存时间。这是可选属性,默认值为空字符 ("")

如在Web.config中加入配置:

<system.web>

    <caching>

        <outputCacheSettings>

            <outputCacheProfiles>

                <add name="CacheTest" duration="50" />

            </outputCacheProfiles>

        </outputCacheSettings>

</caching>

</system.web>

 

页面中声明:<%@ OutputCache CacheProfile="CacheTest" VaryByParam="none" %>

 

注意:用户控件(.ascx 文件)中的 @ OutputCache 指令不支持此属性。在页中指定此属性时,属性值必须与 outputCacheSettings 节下面的 outputCacheProfiles 元素中的一个可用项的名称匹配。如果此名称与配置文件项不匹配,将引发异常。

 

VaryByControl :通过用户控件文件中包含的服务器控件来改变缓存(值是控件ID,多控件用分号隔开)。

<%@ OutputCache Duration="60" VaryByParam="none" VaryByControl="DropDownList1" %>

 

 

页面输出缓存API

Response类的Cache属性用于获取页面缓存策略。该方式的核心是调用System.Web.HttpCachePolicy。该类主要包含用于设置缓存特定的HTTP标头的方法和用于控制ASP.NET页面输出缓存的方法。与.NET Framework 1.x中的HttpCachePolicy类相比,.NET Framework 2.0中的HttpCachePolicy类得到了扩充和发展。主要是增加了一些重要方法,例如,SetOmitVarStar方法等。由于HttpCachePolicy类方法众多,下面简要说明几个常用方法。

 

·    SetExpires方法:用于设置缓存过期的绝对时间。它的参数是一个DataTime类的实例,表示过期的绝对时间。

protected void Page_Load(object sender, EventArgs e)

{

       //相当于@OutputCache指令中的Duration属性

       Response.Cache.SetExpires(DateTime.Now.AddSeconds(10));//表示输出缓存时间是60秒,并且页面不随任何GETPOST参数改变,等同于“<%@ OutputCache Duration="60" VaryByParam="none" %>”

       Response.Cache.SetExpires(DateTime.Parse("6:00:00PM"));//设置缓存过期的绝对时间是当日下午6时整

·    SetLastModified方法:用于设置页面的Last-Modified HTTP标头。Last-Modified HTTP标头表示页面上次修改时间,缓存将依靠它来进行计时。如果违反了缓存限制层次结构,此方法将失败。该方法的参数是一个DataTime类的实例。

·    SetSlidingExpiration方法:该方法将缓存过期从绝对时间设置为可调时间。其参数是一个布尔值。当参数为true时,Cache-Control HTTP标头将随每个响应而更新。此过期模式与相对于当前时间将过期标头添加到所有输出集的IIS配置选项相同。当参数为False时,将保留该设置,且任何启用可调整过期的尝试都将静态失败。此方法不直接映射到HTTP标头。它由后续模块或辅助请求来设置源服务器缓存策略。

·    SetOmitVaryStar方法:ASP.NET 2.0新增的方法。用于指定在按参数进行区分时,响应是否应该包含vary:*标头。方法参数是一个布尔值,若要指示HttpCachePolicy不对其VaryByHeaders属性使用*值,则为true;否则为false

·    SetCacheability方法:用于设置页面的Cache-Control HTTP标头。该标头用于控制在网络上缓存文档的方式。该方法有两种重载方式,所不同的是参数。一种重载方法的参数是HttpCacheability枚举值,包括NoCachePrivatePublicServerServerAndNoCacheServerAndPrivate(有关这些枚举值的定义,可参考MSDN)。另一种方法的参数有两个,一个参数是HttpCacheability枚举值,另一个参数是字符串,表示添加到标头的缓存控制扩展。需要注意的是,仅当与PrivateNoCache指令一起使用时,字段扩展名才有效。如果组合不兼容的指令和扩展,则此方法将引发无效参数异常。

 

页面局部缓存

控件缓存

这种方式允许将需要缓存的信息包含在一个用户控件内,然后,将该用户控件标记为可缓存的,以此来缓存页面输出的部分内容。该选项允许缓存页面中的特定内容,而没有缓存整个页面,因此,每次都需重新创建整个页。例如,如果要创建一个显示大量动态内容(如股票信息)的页,其中有些部分为静态内容(如每周总结),这时可以将静态部分放在用户控件中,并允许缓存这些内容。

 

ASP.NET中,提供了UserControl这种用户控件的功能。一个页面可以通过多个UserControl来组成。只需要在某个或某几个UserControl里设置缓存。

 

WebUserControl1.ascx

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="WebUserControl1.ascx.cs" Inherits="CacheWebApp._16_4_5.WebUserControl1" %>

<%@ OutputCache Duration="60" VaryByParam="none" %>

<%=DateTime.Now %>   

 

调用该控件的页面WebForm1.aspx代码:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="CacheWebApp._16_4_5.WebForm1" %>

<%@ Register src="WebUserControl1.ascx" tagname="WebUserControl1" tagprefix="uc1" %>

<html xmlns="http://www.w3.org/1999/xhtml" >

<head runat="server">

    <title>控件缓存</title>

</head>

<body>

    <form id="form1" runat="server">

    页面的:<%=DateTime.Now %>    

    控件的:<uc1:WebUserControl1 ID="WebUserControl11" runat="server" />

    </form>

</body>

</html>

 

缓存后替换

与控件缓存正好相反。它对整个页面进行缓存,但是页中的某些片段是动态的,因此不会缓存这些片段。ASP.NET页面中既包含静态内容,又包含基于数据库数据的动态内容。静态内容通常不会发生变化。因此,对静态内容实现数据缓存是非常必要的。然而,那些基于数据的动态内容,则不同。数据库中的数据可能每时每刻都发生变化,因此,如果对动态内容也实现缓存,可能造成数据不能及时更新的问题。对此问题如果使用前文所述的控件缓存方法,显然不切实际,而且实现起来很繁琐,易于发生错误。

 

ASP.NET 2.0提供了缓存后替换功能:

·    Substitution控件能够指定页面输出缓存中需要以动态内容替换该控件的部分,即允许对整页面进行输出缓存,然后,使用Substitution控件指定页中免于缓存的部分。需要缓存的区域只执行一次,然后从缓存读取,直至该缓存项到期或被清除。Substitution控件指定的部分,在每次请求页面时都执行。

 

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm2.aspx.cs" Inherits="CacheWebApp._16_4_5.WebForm2" %>

<%@ OutputCache Duration="60" VaryByParam="none" %>

...

页面缓存的时间:<%= DateTime.Now.ToString() %>  

真实(替换)的时间:<asp:Substitution ID="Substitution1" runat="server" MethodName="getCurrentTime" />

...

 

后台代码:

public partial class WebForm2 : System.Web.UI.Page

{

    public static string getCurrentTime(HttpContext context)

    {

        return DateTime.Now.ToString();

   }

}

1) 此方法必须被定义为静态方法;

2) 此方法必须接受HttpContext类型的参数;

3) 此方法必须返回String类型的值。

 

注意:

·    Substitution控件无法访问页上的其他控件,无法检查或更改其他控件的值。但是代码确实可以使用传递给它的参数来访问当前页上下文。

·    在缓存页包含的用户控件中可以包含Substitution控件。但是,在输出缓存用户控件中不能放置Substitution控件。

·    Substitution控件不会呈现任何标记,其位置所显示内容完全取决于所定义方法的返回字符串。

 

Substitution控件API应用

需要注意的是回调方法必须是线程安全的,可以是作为容器的页面或者用户控件中的静态方法,也可以是其他任意对象上的静态方法或实例方法。

 

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm3.aspx.cs" Inherits="CacheWebApp._16_4_5.WebForm3" %>

<%@ OutputCache Duration="60" VaryByParam="none" %>

...

页面缓存的时间:<asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>

真实(缓存替换)的时间:<asp:PlaceHolder ID="PlaceHolder1" runat="Server"></asp:PlaceHolder>

...

 

页面后台:  

protected void Page_Load(object sender, EventArgs e)

{   

    Substitution Substitution1 = new Substitution();//创建一个Substitution   

    Substitution1.MethodName = "GetCurrentDateTime";//指定调用的回调方法名

    PlaceHolder1.Controls.Add(Substitution1);       

    Label1.Text=DateTime.Now.ToString();   

}

public static string GetCurrentDateTime(HttpContext context)

{

    return DateTime.Now.ToString();

}

 

System.Web.Caching

System.Web.Caching命名空间提供用于缓存服务器上常用数据的类。此命名空间包括 Cache 类,该类是一个字典,您可以在其中存储任意数据对象,如哈希表和数据集。它还为这些对象提供了失效功能,并为您提供了添加和移除这些对象的方法。您还可以添加依赖于其他文件或缓存项的对象,并在从 Cache 对象中移除对象时执行回调以通知应用程序。

 

// 获取当前应用程序指定CacheKeyCache对象值

public static object GetCache(string CacheKey)

{

    System.Web.Caching.Cache objCache = HttpRuntime.Cache;

    return objCache[CacheKey];

}

 

// 设置当前应用程序指定CacheKeyCache对象值

public static void SetCache(string CacheKey, object objObject)

{

    System.Web.Caching.Cache objCache = HttpRuntime.Cache;

    objCache.Insert(CacheKey, objObject);

}

 

/// <summary>

/// 设置当前应用程序指定CacheKeyCache对象值

/// </summary>

/// <param name="CacheKey">索引键值</param>

/// <param name="objObject">缓存对象</param>

/// <param name="absoluteExpiration">绝对过期时间</param>

/// <param name="slidingExpiration">最后一次访问所插入对象时与该对象过期时之间的时间间隔</param>

public static void SetCache(string CacheKey, object objObject, DateTime absoluteExpiration, TimeSpan slidingExpiration)

{

    System.Web.Caching.Cache objCache = HttpRuntime.Cache;

    objCache.Insert(CacheKey, objObject, null, absoluteExpiration, slidingExpiration);

}       

 

protected void Page_Load(object sender, EventArgs e)

{

    string CacheKey = "cachetest";

    object objModel = GetCache(CacheKey);//从缓存中获取

    if (objModel == null)//缓存里没有

    {

        objModel = DateTime.Now;//把当前时间进行缓存

        if (objModel != null)

        {

            int CacheTime = 30;//缓存时间30

            SetCache(CacheKey, objModel, DateTime.Now.AddSeconds(CacheTime), TimeSpan.Zero);//写入缓存

        }

    }

    Label1.Text = objModel.ToString();

}

 

文件缓存依赖

这种策略让缓存依赖于一个指定的文件,通过改变文件的更新日期来清除缓存。

                                              

/// 获取当前应用程序指定CacheKeyCache对象值

public static object GetCache(string CacheKey)

{

    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(string CacheKey, 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 void Page_Load(object sender, EventArgs e)

{

    string CacheKey = "cachetest";

    object objModel = GetCache(CacheKey);//从缓存中获取

    if (objModel == null) //缓存里没有

    {

        objModel = DateTime.Now;//把当前时间进行缓存

        if (objModel != null)

        {

            //依赖 C:\\test.txt 文件的变化来更新缓存

            System.Web.Caching.CacheDependency dep = new System.Web.Caching.CacheDependency("C:\\test.txt");

            SetCache(CacheKey, objModel, dep);//写入缓存

        }

    }

    Label1.Text = objModel.ToString();

}

 

当改变test.txt的内容时,缓存会自动更新。这种方式非常适合读取配置文件的缓存处理。如果配置文件不变化,就一直读取缓存的信息,一旦配置发生变化,自动更新同步缓存的数据。

 

数据库缓存依赖

对数据库的缓存还是显得特别重要,上面几种方式都可以实现部分数据缓存功能。但问题是我们的数据有时候是在变化的,这样用户可能在缓存期间查询的数据就是老的数据,从而导致数据的不一致。那有没有办法做到,数据如果不变化,用户就一直从缓存中取数据,一旦数据变化,系统能自动更新缓存中的数据,从而让用户得到更好的用户体验。

 

解决方法:SqlCacheDependency数据库缓存依赖。 

 

第一步: 修改web.config,让项目启用SqlCacheDependency

<?xml version="1.0"?>

<configuration>

    <appSettings/>

    <connectionStrings>

        <add name="strcodematic" connectionString="data source=127.0.0.1;initial catalog=codematic;user id=sa;password=" providerName="System.Data.SqlClient" />

    </connectionStrings>

    <system.web>

        <caching>

            <sqlCacheDependency enabled="true" pollTime="6000">

                <databases>

                    <add name="codematic" connectionStringName="strcodematic" />

                </databases>

            </sqlCacheDependency>         

        </caching>   

...

    </system.web>

</configuration>

 

 

第二步:执行下述命令,为数据库启用缓存依赖。如果要配置SqlCacheDependency,则需要以命令行的方式执行。

aspnet_regsql.exe工具位于Windows\\Microsoft.NET\\Framework\\[版本]文件夹中。

 

aspnet_regsql -C "data source=127.0.0.1;initial catalog=codematic;user id=sa;password=" -ed -et -t "P_Product"

参数-C后面的字符串是连接字符串(请替换成自己所需要的值),

参数-t后面的字符串是数据表的名字。

 

命令执行后,在指定的数据库中会多出一个AspNet_SqlCacheTablesForChangeNotification表。

 

注意:

要使得7.0或者2000版本以上的SQLServer支持SqlCacheDependency特性,需要对数据库服务器执行相关的配置。

有两种方法配置SQLServer

使用aspnet_regsql命令行工具,

使用SqlCacheDependencyAdmin类。

 

例如:

aspnet_regsql -S "server" -E -d "database" –ed 或者

aspnet_regsql -S "server" -E -d "database" -et -t "table"

如果是Sql验证的话要把-E换成,-U (用户名),-P (密码)

 

以下是该工具的命令参数说明:

-? 显示该工具的帮助功能;

-S 后接的参数为数据库服务器的名称或者IP地址;

-U 后接的参数为数据库的登陆用户名;

-P 后接的参数为数据库的登陆密码;

-E 使用当前登录用户的 Windows 集成认证进行身份验证。

-d 后接参数为对哪一个数据库采用SqlCacheDependency功能;

-C 连接数据库的连接字符串。如果您指定服务器(-S)和登录(-U-P,或 -E)信息,则此选项不是必需的,因为连接字符串已经包含这些信息。

-t 后接参数为对哪一个表采用SqlCacheDependency功能;

-ed 允许对数据库使用SqlCacheDependency功能;

-dd 禁止对数据库采用SqlCacheDependency功能;

-et 允许对数据表采用SqlCacheDependency功能;

-dt 禁止对数据表采用SqlCacheDependency功能;

-lt 列出当前数据库中有哪些表已经采用sqlcachedependency功能。

 

 

第三步:在代码中使用缓存,并为其设置SqlCacheDependency依赖: 

/// 获取当前应用程序指定CacheKeyCache对象值

public static object GetCache(string CacheKey)

{

    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(string CacheKey, 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 void Page_Load(object sender, EventArgs e)

{

    string CacheKey = "cachetest";

    object objModel = GetCache(CacheKey);//从缓存中获取

    if (objModel == null)//缓存里没有

    {

        objModel = GetData();//把当前时间进行缓存

        if (objModel != null)

        {

            //依赖数据库codematic中的P_Product表变化 来更新缓存

            System.Web.Caching.SqlCacheDependency dep = new System.Web.Caching.SqlCacheDependency("codematic", "P_Product");

            SetCache(CacheKey, objModel, dep);//写入缓存

        }

    }        

    GridView1.DataSource = (DataSet)objModel;

    GridView1.DataBind();

}

 

 

//查询数据

private DataSet GetData()

{

    string conString = "data source=127.0.0.1;initial catalog=codematic;user id=sa;password=";

    string strSQL = "SELECT * FROM P_Product";

    SqlConnection myConnection = new SqlConnection(conString);

    DataSet ds = new DataSet();

    myConnection.Open();

    SqlDataAdapter adapter = new SqlDataAdapter(strSQL, myConnection);

    adapter.Fill(ds, "Product");

    myConnection.Close();

    return ds;

}

posted @ 2012-01-11 09:49  AIの海雅  阅读(322)  评论(0编辑  收藏  举报