上一篇文章中我們提出了了片斷緩存的基本方式,也就是構建HtmlHelper的擴展方法Cache,接受一個 用於生成字符串的委托對象。在緩存命中時,則直接返回緩存中的字符串片斷,否則則使用委托生成的內 容。因此,緩存命中時委托的開銷便節省了下來。不過這個方法並不實用,如果您要緩存大片的HTML,還 需要准備一個Partial View,再用它來生成網頁片段:
<%= Html.Cache(..., () => Html.Partial("MyPartialViewToCache")) % >
但是在實際開發過程中,我們最樂於看到的使用方法,應該只是使用某個標記來“圍繞”一段現有的 代碼。也就是說,我們希望的API使用方式可能是這樣的:
<% Html.Cache("cache_key", DateTime.Now.AddSeconds(10), () => { % >
<% foreach (var article in Model.Articles) { %>
<p><%= article.Body %></p>
<% } %>
<% }); % >
我們可以從這種“表現形式”上推斷出這個Cache方法的簽名:
public static void Cache(
this HtmlHelper htmlHelper,
string cacheKey,
CacheDependency cacheDependencies,
DateTime absoluteExpiration,
TimeSpan slidingExpiration,
Action action)
{
...
}
與前一個擴展相比,最後一個委托參數變成了Action,而不是Func<string>。這是因為ASP.NET 頁面在編譯時,會將頁面Cache塊中的代碼,編譯為內容的輸出方式——這點在之前的文章中已經有過比 較詳細的描述。不過有一點還是與之前相同的,我們要省下的是action委托的開銷。也就是說,如果緩存 命中,則不執行action。緩存沒有命中,則執行action,獲得action生成的字符串,加入緩存並輸出。
看似比較簡單,但這裡有個問題:如之前的Func<string>參數,我們執行後自然可以獲得一個 字符串作為結果。但是現在是個action,執行後它又把內容輸出到什麼地方去,我們又該如何得到這裡生 成的字符串呢?根據頁面輸出行為,我們可以推斷出頁面上的內容是被寫入一個HtmlTextWriter中的。那 麼,這個HtmlTextWriter又是如何生成的呢?
它是根據Page類型的CreateHtmlTextWriter方法生成的:
protected virtual HtmlTextWriter CreateHtmlTextWriter(System.IO.TextWriter tw) { ... }