本文英文原版以及代碼下載:
http://aspnet.4guysfromrolla.com/articles/121306-1.aspx
ASP.NET 2.0中的Output Caching
導(dǎo)言:
要想提升web application的性能的話,使用caching技術(shù)是肯定能實(shí)現(xiàn)的.Caching利用一些操作將結(jié)果存儲(chǔ)在一個(gè)本地可以快速訪問的地方.在ASP.NET version 1.0里引入了2種技術(shù):
.Output Caching -在特定的時(shí)間段內(nèi),將一個(gè)ASP.NET web頁面或User Control的完整代碼數(shù)據(jù)進(jìn)行緩存.
.Data Caching—將objects對(duì)象存儲(chǔ)在web server的內(nèi)存里,這些存儲(chǔ)在內(nèi)存里的數(shù)據(jù)可以通過編程來訪問.
關(guān)于ASP.NET 1.x緩存技術(shù)的更深入的探討,可參閱Scott McFarland的文章《Caching with ASP.NET》,以及Steve Smith的《ASP.NET Caching: Techniques and Best Practices》.
在ASP.NET 2.0,緩存系統(tǒng)已經(jīng)擴(kuò)展到包含SQL cache dependencies, cache profiles, 以及post-cache substitution.在ASP.NET 2.0 QuickStarts( http://quickstarts.asp.net/QuickStartv20/aspnet )的“Caching for Performance”部分,對(duì)ASP.NET 2.0里的caching進(jìn)行了很好的綜述.本文探究ASP.NET 2.0中的output caching,最開始我們將對(duì)output caching進(jìn)行綜述,接著我們將詳細(xì)的考察如何利用fragment caching和post-cache substitution技術(shù)來創(chuàng)建一個(gè)包含cached 和 non-cached代碼的頁面.
Output Caching綜述
Output caching是這樣提升ASP.NET應(yīng)用程序的性能的,它將一個(gè)ASP.NET web頁面的代碼緩存起來,而不是對(duì)頁面進(jìn)行重新繪制.打個(gè)比方,比如有一個(gè)ASP.NET頁面,該頁面將一個(gè)名為Employees的數(shù)據(jù)庫的記錄顯示出來, 顧名思義,該表存儲(chǔ)的是當(dāng)前員工的信息.如果不進(jìn)行緩存的話,每當(dāng)訪問該頁面的時(shí)候,都會(huì)造成對(duì)數(shù)據(jù)庫的連接,對(duì)表的請(qǐng)求,最后將結(jié)果返回給請(qǐng)求客戶端.但是,雇員信息隔多久才會(huì)有更改的情況呢?可能一天,那么對(duì)數(shù)據(jù)庫的頻繁請(qǐng)求也太過了吧.如果利用output caching的話,在初次對(duì)頁面的訪問時(shí),對(duì)要返回的HTML將在一定的時(shí)間進(jìn)行緩存.在這個(gè)時(shí)間內(nèi),如果某個(gè)用戶請(qǐng)求該頁面,就將緩存數(shù)據(jù)返回。這樣便節(jié)省了數(shù)據(jù)庫訪問和頁面繪制的系統(tǒng)開銷.
這就是一個(gè)簡單的output caching。要貫徹它的話,只需要簡單的在頁面頂部添加聲明
<% @OutputCache %> ,像這樣:
<%@ Page ... %>
<%@ OutputCache Duration="duration" VaryByParam="paramList" %>
其中,duration就是要緩存的秒數(shù). paramList是一系列的參數(shù),這些參數(shù)的值將對(duì)緩存產(chǎn)生影響.打個(gè)比方,如果某個(gè)頁面只需要將某個(gè)特定部門的員工信息顯示出來,而到底是哪個(gè)部門則由查詢參數(shù)來決定,在這種情況下,我們就可以利用該參數(shù)來對(duì)緩存施加影響.具體來說,比如我們想通過訪問ShowEmployees.aspx?DepartmentID=departmentID這個(gè)頁面來展示某個(gè)部門的員工,如果沒有通過參數(shù)對(duì)緩存施加影響,當(dāng)一個(gè)用戶訪問 ShowEmployees.aspx?DepartmentID=Sales頁面時(shí),那么將返回Sales部門的員工信息,并對(duì)頁面進(jìn)行緩存,而如果在緩存期間恰好有另一個(gè)用戶訪問ShowEmployees.aspx?DepartmentID=IT頁面,那么他將會(huì)看到緩存的sales部門而不是IT部門的員工信息.
為解決這個(gè)問題,我們僅僅需要通過參數(shù)DepartmentID來使output cache引擎來實(shí)現(xiàn)多樣化緩存,如下:
<%@ OutputCache Duration="duration" VaryByParam="DepartmentID" %>
要通過所有的參數(shù)來實(shí)現(xiàn)緩存多樣化,可以使用星號(hào)(*);如果不使用參數(shù),使用"None".
Output Caching技巧
雖然實(shí)現(xiàn)output caching很容易—僅僅添加<%@ OutputCache %>標(biāo)記,不過仍然有一些技巧值得我們關(guān)注.正如前面探討的,對(duì)緩存實(shí)施多樣化很重要,這樣我們便可以根據(jù)輸入?yún)?shù)的值進(jìn)行恰當(dāng)?shù)木彺?除了VaryByParam,還可以考慮使用VaryByX操作。比如,我們可以根據(jù)瀏覽器的不同實(shí)施不同的緩存,還有如果有一個(gè)多語言版本的網(wǎng)站,你可以根據(jù)使用語言情況的不同來進(jìn)行不同的緩存.關(guān)于根據(jù)HTTP headers 或 custom values的不同來進(jìn)行不同緩存的具體細(xì)節(jié)可參閱文章《ASP.NET Caching: Techniques and Best Practices》
考察Ouptut Caching的內(nèi)部機(jī)制
在ASP.NET里,Output caching是作為一個(gè)HTTP Module來貫徹的.具體來說就是 System.Web.Caching命名空間里的OutputCacheModule類.一個(gè)HTTP Module對(duì)一個(gè)request 的生命周期內(nèi)的事件進(jìn)行監(jiān)聽,如果觸發(fā)了某個(gè)具體的事件就執(zhí)行代碼.該OutputCacheModule HTTP Module對(duì)應(yīng)ResolveRequestCache 和 UpdateRequestCache.
在ResolveRequestCache事件里,該module判斷是否有output caching請(qǐng)求,如果是,則返回一個(gè)緩存版本,如果沒有所需要的緩存版本的話就呈現(xiàn)正常頁面.在事件結(jié)束時(shí)又觸發(fā) UpdateRequestCache事件,該module將對(duì)rendered output進(jìn)行緩存(如果該頁面被設(shè)置為支持output caching的話).下圖對(duì)OutputCacheModule module要執(zhí)行的這些作業(yè)進(jìn)行了簡單的描述,雖然簡單了點(diǎn),但概括了總體的流程.
圖1
如果想在緩存到期之前就終止緩存的話,有2個(gè)選擇。一是通過編程調(diào)用 Response.RemoveOutputCacheItem(path)方法來移除某個(gè)頁面的output cached,其中path是該頁面的相對(duì)路徑.另外,你還可以對(duì)output cache添加外部依賴,就像在文章
《Caching Page Output with Cache Key Dependencies》里探討的那樣.比如SQL Cache Dependencies,詳情請(qǐng)參閱ASP.NET 2.0 QuickStarts的的《SQL Cache Invalidation》部分(
http://quickstarts.asp.net/QuickStartv20/aspnet/doc/caching/SQLInvalidation.aspx
).
僅僅對(duì)頁面的一部分進(jìn)行Output Caching
默認(rèn)情況下,output caching是針對(duì)整個(gè)頁面緩存.不過在某些時(shí)候,我們希望頁面的某些部分保持“刷新”(dynamic)。我們希望將那些系統(tǒng)開銷大,不怎么變化的項(xiàng)——比如,要顯示的數(shù)據(jù)進(jìn)行緩存,而將廣告、與某個(gè)用戶相關(guān)的數(shù)據(jù)或其它頻繁改變的信息保持"刷新".在ASP.NET 1.x里,我們只能通過fragment caching來實(shí)現(xiàn),這樣就達(dá)到了“頁面的局部緩存而其它部分保持刷新”的目的.在ASP.NET 2.0也支持fragment caching,同時(shí)引入了post-cache substitution model,利用它我們可以實(shí)現(xiàn)“緩存頁面,且保持某些部分刷新”的效果.讓我們先看看fragment caching,再將注意力轉(zhuǎn)移到post-cache substitutions.
Fragment caching原理在于創(chuàng)建一個(gè)包含User Control的頁面,該頁面沒有用到output caching而由其包含的User Control使用output caching.本文的下載代碼里包含了一個(gè)簡單的示例,里面包含一個(gè)CachedUserControl.ascx用戶控件,它將一個(gè)數(shù)據(jù)庫表的記錄顯示出來,同時(shí)將檢索數(shù)據(jù)的date/time值也反映出來.該User Control包含一個(gè) <% @OutputCache %>聲明,如下:
<%@ Control ... %>
<%@ OutputCache Duration="15" VaryByParam="None" %>
... markup that displays records from a database table ...
包含該User Control的頁面并不包含<% @OutputCache %>聲明.最終的結(jié)果是每次登錄頁面的時(shí)候都會(huì)重新繪制頁面,但在每隔15秒的時(shí)間間隔內(nèi),該User Control只呈現(xiàn)一次(自然,也只訪問數(shù)據(jù)庫一次).
如下的截屏顯示的是初次登錄頁面的情形。我們注意到頁面和User Control顯示的date/time值是一樣的.隔幾秒后再次登錄頁面,因?yàn)閷?duì)User Control進(jìn)行了緩存,頁面的date/time值改變了,而User Control顯示的date/time值依然是初次登錄時(shí)的值.
圖2
圖3
除了本文的下載代碼外,你還可以參閱文章《如何使用 Visual C# .NET 在 ASP.NET 中執(zhí)行片段緩存》( http://support.microsoft.com/default.aspx/kb/308378 ),看如何按部就班的使用fragment caching.
通過Post-Cache Substitutions對(duì)緩存頁面的局部保持"刷新"
ASP.NET 2.0新增加了一項(xiàng)技術(shù)post-cache substitutions—它可以將緩存的和需要"刷新"的內(nèi)容有機(jī)的集合起來.就像其名稱揭示的那樣,該方法可以允許在一個(gè)使用了output caching的頁面里,對(duì)緩存的內(nèi)容實(shí)施“刷新”.你可以通過2種途徑來使用它:
.Declaratively—使用Substitution控件來指定頁面的動(dòng)態(tài)刷新部分(dynamic portion). 你需要?jiǎng)?chuàng)建一個(gè)方法,用這些控件來調(diào)用這個(gè)方法來獲取動(dòng)態(tài)刷新部分的rendered markup.
.Programmatically— Response.WriteSubstitution(callback)method可以通過編程的方式注入一個(gè)response substitution模塊。其中,參數(shù)callback是對(duì)某個(gè)方法的委托(delegate),這個(gè)方法被調(diào)用來獲取要發(fā)送出去的markup.
要使用declarative方式的話,你只需要在output cached頁面上要注入動(dòng)態(tài)數(shù)據(jù)(dynamic data)的地方添加一個(gè)Substitution控件,如下:
<%@ Page ... %>
<%@ OutputCache Duration="duration" VaryByParam="paramList" %>
...
<asp:Substitution ID="id" runat="server" MethodName="method" />
...
其中MethodName(string)屬性指定了一個(gè)頁面后臺(tái)代碼類里的一個(gè)靜態(tài)方法,該方法接受一個(gè)HttpContext object對(duì)象,返回string.比如,假設(shè)有一個(gè)包含緩存數(shù)據(jù)的頁面,同時(shí)我們又想在頁面上包含一個(gè)動(dòng)態(tài)信息(比如,一個(gè)廣告).這種情況下,我們?cè)陧撁嫔舷M@示該信息的區(qū)域添加一個(gè)Substitution控件:
<asp:Substitution ID="DynamicMessage" runat="server" MethodName="GetMessage" />
這里我們將MethodName指定為GetMessage. 因此,我需要在頁面的后臺(tái)代碼里創(chuàng)建一個(gè)名為GetMessage,且返回一個(gè)string的靜態(tài)方法:
'VB
Private Shared Function GetMessage(ByVal context As HttpContext) As String
Return "This ad brought to you by the time " & DateTime.Now.ToString()
End Function
// C#
private static string GetMessage(HttpContext context)
{
return "This ad brought to you by the time " + DateTime.Now.ToString();
}
當(dāng)?shù)卿涰撁鏁r(shí),像通常那樣將頁面內(nèi)容進(jìn)行緩存。在后續(xù)的登錄時(shí),雖然頁面仍然被緩存,但OutputCacheModule會(huì)調(diào)用GetMessage方法并將其結(jié)果顯示在頁面上恰當(dāng)?shù)奈恢?
結(jié)論
ASP.NET的output caching屬性允許對(duì)一個(gè)頁面或User Control的整個(gè)HTML輸入進(jìn)行緩存,這有助于提升應(yīng)用程序的總體性能.output caching邏輯是由OutputCacheModule來處理的.有時(shí)候,需要對(duì)頁面的某個(gè)部分進(jìn)行緩存,而其它部分則要保持刷新狀態(tài),為此,ASP.NET 2.0提供了2種解決辦法:fragment caching 和 post-cache substitutions.對(duì)fragment caching而言,沒有對(duì)頁面實(shí)施output caching,對(duì)要實(shí)行緩存的部分我們可以使用User Control來實(shí)行,該用戶控件被設(shè)置為使用output caching.另一個(gè)方法是使用post-cache substitution,此時(shí)需要設(shè)置頁面使用output caching.將Substitution控件添加到頁面以指出頁面的哪個(gè)區(qū)域的內(nèi)容在每次登錄時(shí)都要進(jìn)行動(dòng)態(tài)更新,而不管頁面是否被緩存.Post-cache substitutions是ASP.NET 2.0里新增加的功能.
祝編程快樂!
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
