整頁(yè)輸出緩存
要提升ASP.NET應用程序的性能,最簡(jiǎn)單、最有效的方式就是使用內建的緩存引擎。雖然也能構建自己的緩存,但由于緩存引擎已提供了如此多的功能,所以完全不必如此麻煩。在很大程度上,ASP.NET開(kāi)發(fā)者在Web應用程序中,能將緩存引擎的功能直接包裝到自己的數據表示及訪(fǎng)問(wèn)類(lèi)中。如本文所述,整個(gè)過(guò)程其實(shí)非常簡(jiǎn)單。
ASP.NET的緩存引擎支持三種類(lèi)型的緩存:
整頁(yè)輸出緩存是在一個(gè)頁(yè)被首次請求時(shí),將整個(gè)頁(yè)呈現好的HTML內容緩存下來(lái)。后續請求將直接取用緩存拷貝。 部分緩存是指緩存一部分HTML內容,這類(lèi)似一個(gè)Web用戶(hù)控件的輸出。之所以叫這樣的一個(gè)名字,是因為我們一般說(shuō)“將一部分HTML提交給一個(gè)頁(yè)”。 數據緩存關(guān)注的是單獨的變量或數據項的緩存。它在比以上兩種緩存類(lèi)型都要低的一個(gè)級別上工作。
整頁(yè)輸出緩存
整頁(yè)輸出緩存是最簡(jiǎn)單的緩存類(lèi)型,它只要求為準備緩存的頁(yè)添加一個(gè)預處理指令 OutputCache。使用這種緩存,就不必重新處理一個(gè)頁(yè)的Init, Load,PreRender,Render以及Unload事件。假如那些事件要訪(fǎng)問(wèn)像數據庫那樣的一個(gè)后端系統,那么節省的時(shí)間將是非??捎^(guān)的。ASP.NET可緩存一個(gè)頁(yè)的幾個(gè)變體,并將每個(gè)頁(yè)都與后續請求相關(guān)聯(lián)。所有這些都由 OutputCache預處理指令來(lái)控制,該命令要放在一個(gè)ASPX頁(yè)的頂部,并采用以下格式:
<%@ OutputCache Duration="#ofseconds" Location="Any | Client | Downstream | Server | None" VaryByCustom="browser | customstring" VaryByHeader="headers" VaryByParam="parameter name" %>
OutputCache預處理指令最多可利用5個(gè)相關(guān)的屬性來(lái)控制緩存行為。表 A總結了這些屬性及其含義。
表A
屬性 說(shuō)明
Duration 該屬性指定了網(wǎng)頁(yè)要緩存的時(shí)間(以秒為單位)。通過(guò)為一個(gè)頁(yè)設置該屬性,可為來(lái)自對象HTTP響應建立一個(gè)過(guò)期策略。這是一個(gè)必需屬性。如果不包括它,會(huì )發(fā)生解析器錯誤。注意它指定的是絕對過(guò)期時(shí)間,而非周期性過(guò)期。
Location 用這個(gè)屬性指示W(wǎng)eb服務(wù)器和下游設備(比如代理服務(wù)器和瀏覽器)來(lái)緩存頁(yè)面內容。默認為Any,該屬性并非必需的。
VaryByParam 該屬性使用由分號分隔的字符串列表來(lái)改變輸出緩存。默認情況下,這些字符串對應于隨GET方法屬性發(fā)送的查詢(xún)字符串值,或對應于使用POST方法發(fā)送的一個(gè)參數。如果將該屬性設為多個(gè)參數,輸出緩存將針對指定的每個(gè)參數,包含所請求的文檔的一個(gè)不同版本??赡艿闹蛋∟one、*以及任何有效的查詢(xún)字符串或POST參數名。如果沒(méi)有設置其他屬性,該屬性就是必需的。
VaryByCustom 對自定義輸出緩存需求進(jìn)行表示的任何文本都要包含在這個(gè)屬性中。如果為屬性指派瀏覽器的一個(gè)值,緩存會(huì )根據瀏覽器名稱(chēng)及主版本信息而發(fā)生變化。如果輸入一個(gè)自定義字符串,就必須在應用程序的Global.asax文件中覆蓋GetVaryByCustomString方法。
VaryByHeader 該屬性使用由分號分隔的HTTP標頭列表來(lái)改變輸出緩存。如果屬性設為多個(gè)標頭,輸出緩存將針對指定的每個(gè)標頭,包含所請求文檔的一個(gè)不同的版本。
OutputCache屬性
OutputCache預處理指令可在內存中方便地創(chuàng )建靜態(tài)頁(yè)的單一版本,例如:
<%@ OutputCache Duration=“300" VaryByParam="None" %>
還可根據id查詢(xún)字符串參數來(lái)緩存多個(gè)版本,例如:
<%@ OutputCache Duration=“300" VaryByParam="id" %>
在上述兩個(gè)例子中,網(wǎng)頁(yè)會(huì )在5分鐘(300秒)后從緩存中清除,該數字是由 Duration屬性指定的。
根據自定義信息來(lái)緩存
根據自定義信息來(lái)緩存
使用VaryByCustom屬性,可根據你提供的自定義信息來(lái)創(chuàng )建一個(gè)頁(yè)的緩存版本。例如,要為每種類(lèi)型的瀏覽器創(chuàng )建網(wǎng)頁(yè)的一個(gè)不同版本,可使用以下預處理指令:
<%@ OutputCache
Duration=“300"
VaryByParam="None"
VaryByCustom=“browser”%>使用VaryByCustom,還可根據應用程序特有的信息來(lái)緩存網(wǎng)頁(yè)。例如,要根據當前用戶(hù)的部門(mén)名稱(chēng)來(lái)創(chuàng )建網(wǎng)頁(yè)的緩存版本,可使用以下預處理指令:
<%@ OutputCache
Duration=“300"
VaryByParam="None"
VaryByCustom=“department”%>
然后,在用于Global.asax文件的代碼隱藏類(lèi)中,可覆蓋GetVaryByCustomString方法,如以下VB.NET代碼所示:
Public Overrides Function GetVaryByCustomString( _
ByVal context As System.Web.HttpContext, _
ByVal custom As String) As String
If custom = "department" Then
' return the department for the current user
End If End Function
這里向GetVaryByCustomString方法傳遞了在預處理指令中使用的自定義值。ASP.NET運行庫調用該方法時(shí),你可使用自己的算法,根據輸入值來(lái)判斷當前用戶(hù)所在的部門(mén),并從方法中返回它。
根據標頭信息來(lái)緩存
使用VaryByHeader屬性,可根據網(wǎng)頁(yè)接收到的一個(gè)或多個(gè)HTTP標頭來(lái)創(chuàng )建一個(gè)網(wǎng)頁(yè)的多個(gè)緩存版本。例如,要想根據瀏覽器的語(yǔ)言來(lái)創(chuàng )建和緩存不同的版本,可使用以下預處理指令:
<%@ OutputCache
Duration="60"
VaryByParam="None"
VaryByHeader="Accept-Language" %>
-------------------------------------------------------------
檢查標頭
要查看隨同特定Web請求發(fā)送的各個(gè)HTTP標頭的值,可打開(kāi)ASP.NET頁(yè)的跟蹤功能,具體做法是在網(wǎng)頁(yè)的 Page預處理指令中設置trace和traceMode屬性。另外,也可通過(guò)Visual Studio .NET的屬性頁(yè)來(lái)設置。
-------------------------------------------------------------
除了聲明性地緩存整個(gè)網(wǎng)頁(yè),還可使用由Page類(lèi)揭示的Response對象的 Cache屬性來(lái)程序化地設置一個(gè)頁(yè)的緩存選項。Cache屬性揭示了用于網(wǎng)頁(yè)的 HttpCachePolicy對象,可用它在服務(wù)器上將緩存時(shí)間設為5分鐘,如以下C# 代碼段所示:
private void Page_Init( object sender, System.EventArgs e ) { Response.Cache.SetCacheability(HttpCacheability.Server); Response.Cache.SetExpires(DateTime.Now.AddSeconds(300)); Response.Cache.SetValidUntilExpires(True) }
部分緩存
部分緩存
部分緩存允許只緩存部分HTML,它的效率很高,因為一個(gè)頁(yè)中經(jīng)常變化的部分可與那些不經(jīng)常變化部分的部分合并到一起,同時(shí)仍能從緩存中檢索靜態(tài)的部分。一個(gè)實(shí)例是將“部分緩存”應用于需要調用XML Web服務(wù)的Web用戶(hù)控件。這樣可獲得很高的效率,因為它避免了你的網(wǎng)站與Web服務(wù)過(guò)度緊密地耦合,同時(shí)還能顯著(zhù)提升性能。
要使用部分緩存,同樣可在HTML頁(yè)的頂部放置一條OutputCache預處理指令。但這一次,我們準備把它放到Web用戶(hù)控件的ASCX頁(yè)中。注意使用部分緩存時(shí), Location和VaryByHeader屬性將不再支持,但新增了對VaryByControl屬性的支持。
使用VaryByControl屬性,可用一個(gè)由分號分隔的列表來(lái)指定用戶(hù)控件的一個(gè)或多個(gè)屬性??蔀閷傩灾档拿恳环N組合來(lái)創(chuàng )建緩存的版本。例如,假定你的用戶(hù)控件揭示出一個(gè)自定義的 State屬性,它控制著(zhù)要顯示用戶(hù)控件的哪些元素。使用以下預處理指令,可針對 State的每個(gè)值來(lái)緩存控件所具體呈現的一個(gè)版本:
<%@ OutputCache Duration="300" VaryByControl="State" %>
但在緩存Web用戶(hù)控件時(shí),記住ASP.NET運行庫會(huì )直接用緩存的HTML來(lái)替換實(shí)際控件,忽略平常會(huì )發(fā)生的任何控件處理。這暗示著(zhù)在網(wǎng)頁(yè)中執行的代碼不能程序化地操縱一個(gè)緩存的用戶(hù)控件或者它的任何屬性。換言之,Web用戶(hù)控件必須能完全自主,并能通過(guò)它的 Load和Init事件來(lái)初始化自己,以便有效地緩存。
也可聲明性地完成部分緩存,方法是使用一個(gè)屬性而不是使用OutputCache預處理指令。在代碼隱藏文件中, PartialCaching屬性可放在從UserControl派生的一個(gè)類(lèi)中,使ASP.NET運行庫能夠讀取它,并相應地緩存呈現好的HTML。例如,以下來(lái)自代碼隱藏類(lèi)的聲明能根據查詢(xún)字符串中的 id值,將Web用戶(hù)控件緩存5分鐘。
<PartialCaching(300, "id", Nothing, Nothing)> _ Public MustInherit Class MyHeaderControl Inherits System.Web.UI.UserControl
數據緩存
數據緩存
ASP.NET緩存引擎支持的最后一種緩存類(lèi)型是“數據緩存”。根據定義,它的工作級別要低于整頁(yè)輸出緩存和部分緩存。假如幾個(gè)網(wǎng)頁(yè)都要使用相同的數據(例如一個(gè)產(chǎn)品列表),但要以不同方式來(lái)顯示這些數據,就可考慮使用這種緩存。當然,數據緩存之所以具有性能優(yōu)勢,是因為減少了對后端數據庫的調用次數。
為了在緩存中添加一個(gè)項,需使用Page或UserControl類(lèi)的Cache屬性,因為這兩個(gè)類(lèi)最終都是從Control類(lèi)派生的。 Cache屬性揭示出了System.Web.Caching.Cache對象,利用它可將數據當作鍵和值的一個(gè)組合來(lái)存儲。使用該屬性,開(kāi)發(fā)者可編寫(xiě)代碼來(lái)填充一個(gè)項,并把它放到緩存中;如果該項已經(jīng)存在,就直接將其從緩存中取出。如以下C#代碼所示。
DataTable dt = null; if (this.Cache["Products"] == null) { // Go get the data from the database this.Cache.Insert("Products", dt, null, _ DateTime.Now.AddHours(6), TimeSpan.Zero); } else { dt = this.Cache["Products"] As DataTable; }
上例首先檢查具有Products鍵的項是否在緩存中。如果不在,就從后端數據庫檢索一個(gè)ADO.NET DataTable,并使用Insert方法把它放到緩存中。本例使用的是 Insert的一個(gè)重載版本,它允許為緩存對象指定一個(gè)絕對過(guò)期時(shí)間(6小時(shí)),而不是指定一個(gè)周期性的過(guò)期。相反,如果緩存中已經(jīng)有這個(gè)項,就將其取回,并使用 As表達式,將其強制轉換回一個(gè)DataTable。
對ADO.NET檢索到的數據進(jìn)行緩存時(shí),注意既可像上例那樣緩存DataTable對象,也可緩存整個(gè) DataSet對象,因為兩種對象都同任何數據源完全地斷開(kāi),不會(huì )保持數據庫連接。對數據讀取器(比如 SqlDataReader)進(jìn)行緩存似乎更好一些,因為它們只使用一次(它們是“只進(jìn)”的讀取器),而且在打開(kāi)的情況下將一直占據一個(gè)數據庫連接。
ASP.NET緩存引擎強大的靈活性和功能使其成為創(chuàng )建高性能ASP.NET應用程序時(shí)最重要的特性之一。根據本文提供的基本信息,你可在自己的應用程序輕松引入緩存引擎功能。