下面的代码示例演示如何设置页或用户控件进行输出缓存的持续时间。
<%@ OutputCache Duration="100" VaryByParam="none" %>
下一个代码示例演示如何指示输出缓存按页或用户控件的位置对它们进行缓存,并根据窗体的 POST 方法或查询字符串对窗体参数进行计数。每个收到的具有不同位置或计数参数(或两者)的 HTTP 请求都进行 10 秒的缓存处理。带有相同参数值的任何后继请求都将从缓存中得到满足,直至超过输入的缓存期。
<%@ OutputCache Duration="10" VaryByParam="location;count" %>
有时缓存整个页是不现实的,因为页的某些部分可能在每次请求时都需要更改。在这些情况下,只能缓存页的一部分。执行此操作有两个选项:控件缓存和缓存后替换。
在控件缓存(也称为片段缓存)中,可以通过创建用户控件来包含缓存的内容,然后将用户控件标记为可缓存来缓存部分页输出。该选项允许缓存页中的特定内容,而在每次都重新创建整个页。例如,如果创建的页显示大量动态内容(如股票信息),但也有某些部分是静态的(如每周摘要),则可以在用户控件中创建这些静态部分并将用户控件配置为缓存。
缓存后替换与控件缓存正好相反。它对页进行缓存,但是页中的某些片段是动态的,因此不会缓存这些片段。例如,如果创建的页在设定的时间段内完全是静态的(例如新闻报道页),可以设置为缓存整个页。如果为缓存的页添加旋转广告横幅,则在页请求之间,广告横幅不会变化。然而,使用缓存后替换,可以对页进行缓存,但可以将特定部分标记为不可缓存。在本例中,将广告横幅标记为不可缓存。它们将在每次页请求时动态创建,并添加到缓存的页输出中。有关缓存后替换的更多信息,请参阅动态更新缓存页的部分。
通过创建用户控件来缓存内容,可以将页上需要花费宝贵的处理器时间来创建的某些部分(例如数据库查询)与页的其他部分分离开。只需占用很少服务器资源的部分可以在每次请求时动态生成。
在标识了要缓存的页的部分,并创建了用以包含这些部分中的每个部分的用户控件后,您必须确定这些用户控件的缓存策略。您可以使用 @ OutputCache 指令,或者在代码中使用 PartialCachingAttribute 类,以声明的方式为用户控件设置这些策略。
例如,如果在用户控件文件(.ascx 文件)的顶部包括下面的指令,则该控件的一个版本将在输出缓存中存储 120 秒。
<%@ OutputCache Duration="120" VaryByParam="None" %>
若要在代码中设置缓存参数,可以在用户控件的类声明中使用一个属性。例如,如果在类声明的元数据中包括下面的属性,则该内容的一个版本将在输出缓存中存储 120 秒:
[PartialCaching(120)] public partial class CachedControl : System.Web.UI.UserControl { // Class Code }
有关可在页输出中设置的属性的更多信息,请参阅 @ OutputCache 主题。有关如何开发用户控件的更多信息,请参见 ASP.NET Web 服务器控件概述。
注意 |
---|
由于可在页上嵌套用户控件,您还可以嵌套已放置到输出缓存中的用户控件。可以为页和嵌套的用户控件指定不同的缓存设置。 |
在以声明的方式创建可缓存的用户控件时,可以包括一个 ID 属性,以便以编程方式引用该用户控件实例。但是,在代码中引用用户控件之前,必须验证在输出缓存中是否存在该用户控件。缓存的用户控件只在首次请求时动态生成;在指定的时间到期之前,从输出缓存满足所有的后续请求。确定用户控件已实例化后,可以从包含页以编程方式操作该用户控件。例如,如果通过声明方式将 SampleUserControl
的 ID 分配给用户控件,则可以使用下面的代码检查它是否存在。
protected void Page_Load(object sender, EventArgs e) { if (SampleUserControl != null) // Place code manipulating SampleUserControl here. }
可以为页和页上的用户控件设置不同的输出缓存持续时间值。如果页的输出缓存持续时间长于用户控件的输出缓存持续时间,则页的输出缓存持续时间优先。例如,如果页的输出缓存设置为 100 秒,而用户控件的输出缓存设置为 50 秒,则包括用户控件在内的整个页将在输出缓存中存储 100 秒,而与用户控件较短的时间设置无关。
下面的代码示例演示了当页的缓存持续时间长于用户控件的缓存持续时间时的效果。该页配置为缓存 100 秒。
<%@ 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 秒。
<% @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 秒。
<%@ 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 秒。
<% @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 秒之久。
在使用配置文件的每个 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 指令相同的缓存策略。
Response.Cache.SetExpires(DateTime.Now.AddSeconds(60));
Response.Cache.SetCacheability(HttpCacheability.Public);
Response.Cache.SetValidUntilExpires(true);
当缓存页到期时,以后对该页的请求将导致动态生成的响应。会在指定的持续时间内缓存该响应页。
(十)动态更新缓存页的部分
对页面进行缓存可以大大提高 Web 应用程序的性能。不过,在有些情况下,需要缓存页面的大部分内容,但页面中的某些片段是动态的。例如,如果创建一个页面,其中的新闻故事在设定时间段内完全是静态的,则可以设置为缓存整个页面。如果希望提供在每次页请求时都发生变化的交替出现的广告横幅,则该页中包含该广告的部分需要是动态的。
若要允许缓存某个页面但动态地替换其中的某些内容,可以使用 ASP.NET 缓存后替换。通过使用缓存后替换,将对整个页面进行输出缓存,并将特定的部分标记为不进行缓存。在广告横幅示例中,AdRotator 控件使您可以利用缓存后替换功能,以便为每个用户及在每次刷新页时动态创建广告。
有三种方法可以实现缓存后替换:
以声明方式使用 Substitution 控件。
以编程方式使用 Substitution 控件 API。
以隐式方式使用 AdRotator 控件。
ASP.NET Substitution 控件指定缓存页中动态创建而不进行缓存的部分。将 Substitution 控件放置在该页上要显示动态内容的位置。
在运行时,Substitution 控件调用使用 MethodName 属性指定的方法。该方法必须返回一个字符串,然后该字符串替换 Substitution 控件的内容。该方法必须是 Page 或 UserControl 包含控件上的静态方法。
使用 Substitution 控件可以将客户端可缓存性更改为服务器可缓存性,以便该页面不会在客户端上进行缓存。这样可以确保以后对该页的请求能够再次调用该方法以生成动态内容。
若要以编程方式为缓存页创建动态内容,可以在页代码中将某个方法的名称作为参数传递给 WriteSubstitution 方法来调用该方法。该方法处理动态内容的创建,它采用单个 HttpContext 参数并返回一个字符串。该返回字符串是将在给定位置被替换的内容。通过调用 WriteSubstitution 方法来代替以声明方式使用 Substitution 控件的一个好处是可以调用任意对象的方法,而不只是调用 Page 或 UserControl 对象的静态方法。
调用 WriteSubstitution 方法可以将客户端可缓存性更改为服务器可缓存性,以便该页不会在客户端上进行缓存。这样可以确保以后对该页的请求能够再次调用该方法以生成动态内容。
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 控件,不仅可以更轻松地连接数据库,还使缓存数据库数据变得更容易。只需在 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 是 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。下面将分别介绍这三种情况。
在 Web 应用程序中使用 SQL Cache Invalidation 之前,首先必须执行一些配置步骤。必须将 Microsoft SQL Server 配置为支持 SQL Cache Invalidation,还必须在应用程序的 Web 配置文件中添加必要的配置信息。
可以按照以下两种方法配置 SQL Server:使用 aspnet_regsql 命令行工具,或者使用 SqlCacheDependencyAdmin 类。
使用 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 中选择表的列表。此外,您也可以通过直接在该数据库表中执行查询来检索此信息。
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 方法。
在 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 的所有配置步骤,可以在 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 属性值列出多个数据库和/或多个数据库表。要创建多个依赖关系,只需用分号分隔每个依赖关系即可。
除了在页面输出缓存中使用 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。此选项使您可以最大程度地对 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>
在许多情况下,您需要缓存页面的一部分,而不是整个页面。例如,在您的 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 The