明天的明天 永远的永远 未知的一切 我与你一起承担 ??

是非成败转头空 青山依旧在 几度夕阳红 。。。
  博客园  :: 首页  :: 管理

ASP.NET : Cache 的几种相关运用.

Posted on 2011-01-20 11:50  且行且思  阅读(401)  评论(0编辑  收藏  举报

原文:http://www.codeproject.com/KB/aspnet/AspDotNetCache.aspx

 缓存是在内存中存储很耗时创建的数据的一项技术,也是ASP.NET一个重要特性。例如,你可以缓存那些耗时的复杂查询出来的数据,之后的请求不必再从数据库中取数,直接从缓存中取。通过缓存,可以大大提高应该程序的性能。

 

主要有两种缓存类型:

1.输出缓存

2.数据缓存


1. Output Caching(输出缓存)

使用输出缓存,可以缓存页面最终的生成的HTML。当同一个页面再次请求时,缓存页起作用。ASP.NET不再执行页面的生命周期和相关代码。输出缓存的语法:

1 <%@ OutputCache Duration=60” VaryByParam=”None” %>

 

 

Duration 属性设置页面将缓存60秒,在所有用户的请求中的第一次请求,ASP.NET执行页面代码,把生最终生成的HTML结果呈现给用户,并在缓存保存。如果服务器在60秒内再次接到同一个页面的请求,ASP.NET自动发送缓存中备份页面给用户。如果服务器在缓存过期后接到一个请求,ASP.NE执行页面代码并为下一个60秒创建一个新的HTML缓存。

 <%@ Page Language="C#" MasterPageFile="~/MasterPage.master" AutoEventWireup="true"
        CodeFile="OutputCachingTest.aspx.cs" Inherits="OutputCachingTest" Title="Untitled Page" %>
 <%@ OutputCache Duration="20" VaryByParam="None" %>
 <asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" runat="Server"> 
   <div class="title">Output Cache</div>
   Date: <asp:Label ID="lblDate" runat="server" Text="" />
   Time: <asp:Label ID="lblTime" runat="server" Text="" />       
 </asp:Content>
protected void Page_Load(object sender, EventArgs e)
{
   lblDate.Text = DateTime.Now.ToShortDateString();
   lblTime.Text = DateTime.Now.ToLongTimeString(); 
} 

在本例中, 页面将被缓存20秒。


Cache by Query String (通过查询字符串缓存)

在实际应用中,动态页面是根据参数改变页面内容的。如果你的页面是通过查询字符串来接收信息的,你也可以很容易的根据查询字符串来缓存页面的不同拷贝。VarByParam=”None” 告诉ASP.NET只存储页面的一份拷贝。VarByParam=”*”告诉ASP.NET根据不同的查询字符串存储不同的页面拷贝。

 <%@ OutputCache Duration="60" VaryByParam="*" %>
    <div align="right">
    <a href="OutputCachingTest2.aspx">No Query String</a> | 
    <a href="OutputCachingTest2.aspx?id=1">ID 1</a> | 
    <a href="OutputCachingTest2.aspx?id=2">ID 2</a> | 
    <a href="OutputCachingTest2.aspx?id=3">ID 3</a> |
    <a href="OutputCachingTest2.aspx?id=3&langid=1">ID 3</a>
    </div> 

在同一个页面中,通过传递不同查询字符串ID值,ASP.NET针对每一个ID值存储一份拷贝,该技术在这种情况下利用的非常好,但是也存在一些问题。如果页面接收很广泛的查询字符串,那么,ASP.Net针对每一个查询字符串参数缓存一份拷贝,并且潜在的降低了重用性。这种情况下,你可以在VarByParam属性中指定几个比较重要的查询参数。

<%@OutputCacheDuration="60"VaryByParam="id;langid"%> 

 

如上所设置,ASP.Net根据不同的“id” 或者 “langid”查询字符串值缓存不同的版本


Custom Caching(自定义缓存)

你也可以创建自定义页面缓存处理过程。ASP.NET提供了一种很便捷的方式来创建自定义缓存,通过给VarByCustom属性指定自定义的缓存类型。

 <%@ OutputCache Duration="20" VaryByParam="None" VaryByCustom="browser" %>

 

你需要创建一个方法,该方法生成一个自定义缓存字符串。语法如下:

  public override string GetVaryByCustomString(HttpContext context, string custom)
   { 
      if (custom == "browser")
     {
         return context.Request.Browser.Browser +
                context.Request.Browser.MajorVersion;
      }
      else
      {
        return base.GetVaryByCustomString(context, custom);
     }
  }

 

该方法必须写在global.asax文件中,返回一个字符串值。ASP.Net用这个值来实现缓存。如果不同的请求方法返回相同的字符串值,ASP.net重用缓存页面除非产生了一个新的缓存版本。在上面例子中,GetVaryByCustomString()创建了一个基于浏览器名称的缓存字符串。ASP.Net将根据不同的浏览器请求创建不同的缓存版本。


Control Cache(控件缓存)

上面的缓存技术,能让你很容易的缓存整个页面。但是如果你想缓存指定的控件内容,你可以通过VaryByControl属性来缓存一个控件

 <%@ OutputCache Duration="20" VaryByControl="MyControl_1" %>

在.aspx页面上添加上面代码,ASP.net将缓存 MyControl_1控件20秒,这样ASP.net创建一个“MyControl_1”缓存版本,如果缓存没有过期,ASP.net重用该缓存版本,除非控件代码重新执行过。如果你想创建一个依赖于控件某些属性的控件缓存,ASP.net同样很方便,只需在*.ascx控件页上添加OutPutCache指令。

  <%@ Control Language="C#" AutoEventWireup="true" 
     CodeFile="MyControl.ascx.cs" Inherits="Controls_MyControl" %>
  <%@ OutputCache Duration="20" VaryByControl="EmployeeID" %>
 

 

VaryByControl=”EmployeeID” 告诉ASP.net根据控件属性EmployeeID不同值创建不同的控件缓存版本。

在.ascx.cs 文件中添加属性”EmplyeeID“,用于ASP.net创建缓存

  private int _employeeID;
  public int EmployeeID
  {
     get { return _employeeID; }
     set { _employeeID = value; }
   }
 
   protected void Page_Load(object sender, EventArgs e)
   {
    lblDate.Text = DateTime.Now.ToShortDateString();
    lblTime.Text = DateTime.Now.ToLongTimeString();

    lblEmployeeID.Text = EmployeeID.ToString();
  }

 

在页面上添加控件并设置”EmployeeID“

 <%@ Register Src="Controls/MyControl.ascx" TagName="MyControl" TagPrefix="uc1" %>
 <asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" runat="Server">
    <div align="center">
         <uc1:MyControl ID="MyControl1" runat="server" EmployeeID="1"></uc1:MyControl>
    </div>
 </asp:Content>

 

Cache Profile(缓存配置文件)

ASP.net在web.config文件中定义缓存设置也是相当的方便。假如你在页面中嵌入缓存设置,并且想从20秒改为30秒,然后你必须在所有页面中更改duration值。最好的方式就是在web.config中设置缓存,你可以非常容易管理你的缓存设置。

<system.web>
   <caching>
    <outputCacheSettings >
      <outputCacheProfiles>
        <add name ="ProductItemCacheProfile" duration ="60"/>
      </outputCacheProfiles>
     </outputCacheSettings>
    </caching>
  </system.web>

 

现在你只需要在页面属性中添加CacheProfile=”ProfileName”就可以了。

 <%@ OutputCache CacheProfile ="ProductItemCacheProfile" VaryByParam="None" %>

 

数据缓存(Date Cache)

ASP.net也提供了灵活的数据缓存。你可以把一些耗资源的项添加到对象缓存集合中。Cache是一个键值对集合,添加项到缓存集合中只需要指定一个新的Key名称。

  Cache["Name"= data;

该技术不支持缓存对象的控制。Cache.Insert()提供了5版本的方法重载,通过使用Insert方法,你可以设置缓存的过期策略、优先级、依赖项等。

  date1 = DateTime.Now;
2  Cache.Insert("Date1", date1, null, DateTime.Now.AddSeconds(20), TimeSpan.Zero);

 

Asp.net 允许设置绝对的或者相对的过期策略,但每次只能使用一个。


Cache dependency(缓存依赖项)

同样你也可以在ASP.net中设置缓存依赖项,缓存依赖项允许一个缓存项依赖于另一项资源,但依赖资源改变时,缓存项将自动移除。CacheDependency类用于创建依赖项。这个类有多个构造函数。你可以创建依赖于文件或者文件夹。如果文件或者文件夹改变,缓存将过期。你也可以创建依赖于其它缓存项的依赖项。

  date2 = DateTime.Now;

  string[] cacheKeys = { "Date1" };
  CacheDependency cacheDepn = new CacheDependency(null, cacheKeys);
  Cache.Insert("Date2", date2, cacheDepn);

 

在上例中“Date2“缓存对项依赖于”Date1“缓存项。当”Date1“缓存对象过期时,”Date2"缓存项将自动过期。在 CacheDependency(null, cacheKeys)构造函数中,第一个参数为“null",是因为我们不想创建依赖于文件或者文件夹的缓存。我们只需要传递缓存项的Keys列表,因为我们只想创建依赖于缓存项的依赖项。


Callback Method and Cache Priority(回调函数和缓存优先级)

ASP.net也允许你编写一个回调函数,但缓存项从缓存中移除时,该方法将被触发。也可以设置缓存项的优先级。

   protected void Page_Load(object sender, EventArgs e)

   {
     DateTime? date1 = (DateTime?)Cache["Date1"];
     if (!date1.HasValue) // date1 == null
     {
       date1 = DateTime.Now;
       Cache.Insert("Date1", date1, null, DateTime.Now.AddSeconds(20), TimeSpan.Zero, 
                    CacheItemPriority.Default, 
          new CacheItemRemovedCallback(CachedItemRemoveCallBack));
    }

    DateTime? date2 = (DateTime?)Cache["Date2"];
    if (!date2.HasValue) // date2 == null
    {
     date2 = DateTime.Now;
     Cache.Insert("Date2", date2, null, DateTime.Now.AddSeconds(40), TimeSpan.Zero, 
                   CacheItemPriority.Default, 
         new CacheItemRemovedCallback(CachedItemRemoveCallBack));
    }
 
    // Set values in labels
    lblDate.Text = date1.Value.ToShortDateString();
    lblTime.Text = date1.Value.ToLongTimeString();
 
    lblDate1.Text = date2.Value.ToShortDateString();
    lblTime1.Text = date2.Value.ToLongTimeString();
 
  }
     
  private void CachedItemRemoveCallBack(string key, object value, 
                 CacheItemRemovedReason reason)
  {
    if (key == "Date1" || key == "Date2")
    { 
       Cache.Remove("Date1");
       Cache.Remove("Date2");
    }
  }

如上例所示,我创建了”Date1"和“Date2"缓存。"Date1"20秒后过期,”Date2"40秒,但是你注意到他们同时过期。原因是因为我们注册了一个移除缓存的回调函数。当'Date1"或"Date2"过期时,将调用CachedItemRemoveCallBack方法。在这个方法中,我移除了这两个缓存项。


Asp.net也提供了缓存项的更新回调函数。CacheItemUpdateCallback代理事件就是为这个而设计的。

 
//***********************************************************************************************
1. INTRODUCTION 
  大量的网站页面是采用动态的方式,根据用户提交的不同请求创建生成页面。正如我们所知的,动态页面有助于根据用户要求来提供定制的动态内容。动态页面也利于获取在数据库中每时每刻更新的资料。缺点是为每个用户请求生成同一页面增加了系统开销。 
  ASP.NET 提供了缓存技术有助于我们最大程度地解决这个问题。它能缓存输出的页面,保存在存储器当中,缓存用户请求的内容。缓存的特点可以根据不同方式来定制的。 
  本文主要介绍ASP.NET的缓存技术。介绍其使用方法,以及客户端缓存存在的问题。 
  2. ASP.NET CACHE 
  缓存是把应用程序中需要频繁、快速访问的数据保存在内存中的编程技术。ASP.NET提供三种主要形式的缓存:页面级输出缓存、用户控件级输出缓存(或称为片段缓存)和缓存API。输出缓存和片段缓存的优点是非常易于实现,在大多数情况下,使用这两种缓存就足够了。而缓存API则提供了额外的灵活性(实际上是相当大的灵活性),可用于在应用程序的每一层利用缓存。本文只介绍页面级缓存和用户控件级缓存。 
  2.1. Page Caching 
  作为最简单的缓存形式,输出缓存只是在内存中保留为响应请求而发送的 HTML 的副本。其后再有请求时将提供缓存的输出,直到缓存到期,这样,性能有可能得到很大的提高(取决于需要多少开销来创建原始页面输出 - 发送缓存的输出总是很快,并且比较稳定)。 
  要实现页面输出缓存,只要将一条 OutputCache 指令添加到页面即可: 
  <%@ OutputCache Duration="60" VaryByParam="*" %> 
  如同其他页面指令一样,该指令应该出现在ASPX页面的顶部,即在任何输出之前。它支持五个属性(或参数),其中两个是必需的。 
   Duration:必需属性。页面应该被缓存的时间,以秒为单位。必须是正整数。 
   Location:指定应该对输出进行缓存的位置。如果要指定该参数,则必须是下列选项之一:Any、Client、Downstream、None、Server 或 ServerAndClient。 
   VaryByParam:必需属性。Request 中变量的名称,这些变量名应该产生单独的缓存条目。"none" 表示没有变动。"*" 可用于为每个不同的变量数组创建新的缓存条目。变量之间用 ";" 进行分隔。  
   VaryByHeader:基于指定的标头中的变动改变缓存条目。 
   VaryByCustom:允许在 global.asax 中指定自定义变动(例如,"Browser")。 
  利用必需的 Duration 和 VaryByParam 选项的组合可以处理大多数情况。例如,如果您的产品目录允许用户基于 categoryID 和页变量查看目录页,您可以用参数值为 "categoryID;page" 的 VaryByParam 将产品目录缓存一段时间(如果产品不是随时都在改变,一小时还是可以接受的,因此,持续时间是 3600 秒)。这将为每个种类的每个目录页创建单独的缓存条目。每个条目从其第一个请求算起将维持一个小时。 
  VaryByHeader 和 VaryByCustom 主要用于根据访问页面的客户端对页面的外观或内容进行自定义。同一个 URL 可能需要同时为浏览器和移动电话客户端呈现输出,因此,需要针对不同的客户端缓存不同的内容版本。或者,页面有可能已经针对 IE 进行了优化,但需要能针对 Netscape 或 Opera 完全降低优化(而不仅仅是破坏页面)。 
  2.2. Fragment caching 
  ASP.NET提供了部分缓存或区域缓存Web表单的功能。当希望在特定的页面上实现对缓存更多的控制时,可以使用该技术。 
  为了指定应该被缓存的用户控件,我们利用 @OutputCache 指令,就象整个页面缓存的用法一样。 
  <%@ OutputCache Duration=10 VaryByParam="*" %> 
  该示例将缓存用户控件60秒,并且将针对查询字符串的每个变动、针对此控件所在的每个页面创建单独的缓存条目。 
  <%@ OutputCache Duration="60" VaryByParam="none" 
  VaryByControl="CategoryDropDownList" %> 
  该示例将缓存用户控件60秒,并且将针对CategoryDropDownList控件的每个不同的值、针对此控件所在的每个页面创建单独的缓存条目。 
  还可以通过设置属性Shared=”true”,让使用它的所有页面共享这个控件缓存。 
  3. CONCLUSION AND SUGGESTION 
  应该在应用程序的每一层都实现缓存。向数据层、业务逻辑层、UI 或输出层添加缓存支持。内存现在非常便宜 — 因此,通过以智能的方式在整个应用程序中实现缓存,可以获得很大的性能提高。 
  缓存是一种无需大量时间和分析就可以获得“足够良好的”性能的方法。这里再次强调,内存现在非常便宜,因此,如果您能通过将输出缓存 30 秒,而不是花上一整天甚至一周的时间尝试优化代码或数据库就可以获得所需的性能,您肯定会选择缓存解决方案(假设可以接受 30 秒的旧数据)。缓存正是那些利用 20% 付出获得 80% 回报的特性之一,因此,要提高性能,应该首先想到缓存。不过,如果设计很糟糕,最终却有可能带来不良的后果,因此,您当然也应该尽量正确地设计应用程序。但如果您只是需要立即获得足够高的性能,缓存就是您的最佳选择,您可以在以后有时间的时候再尽快重新设计应用程序。 
  ASP.NET缓存和IE缓存并不是同一个概念,IE缓存可能会导致错误发生,而且很难控制,可以考虑禁止IE缓存,而只采用ASP.NET缓存机制。 
  针对我们的Web系统的特殊性,存在大量的页面针对不同的用户显示不同的数据,因此在采用ASP.NET缓存机制时,请格外小心。可以考虑在缓存机制使用时增加一些必要的参数。