原文地址:http://www.asp.net/learn/mvc/tutorial-15-cs.aspx
在這篇教程里,你會(huì )學(xué)習到利用緩存輸出會(huì )多么顯著(zhù)地改善你的ASP.NET MVC應用的性能。你會(huì )學(xué)習到如何緩存從控制器行為返回的結果。通過(guò)緩存從控制器行為返回的結果,每次新的用戶(hù)調用該行為時(shí),相同的內容不再需要每次都創(chuàng )建一次。
在這篇教程里,你會(huì )學(xué)習到利用緩存輸出會(huì )多么顯著(zhù)地改善你的ASP.NET MVC應用的性能。你會(huì )學(xué)習到如何緩存從控制器行為返回的結果。通過(guò)緩存從控制器行為返回的結果,每次新的用戶(hù)調用該行為時(shí),相同的內容不再需要每次都創(chuàng )建一次。
假設你的ASP.NET MVC應用在一個(gè)名叫Index的視圖里顯示數據庫記錄的列表。通常情況下,每一次一個(gè)用戶(hù)調用控制器行為就返回Index 視圖,而數據庫記錄集則必須從數據庫里通過(guò)執行數據庫查詢(xún)來(lái)返回檢索。
假設,從另外一方面來(lái)說(shuō),你利用了輸出緩存那么你就可以避免任何用戶(hù)調用同一控制器行為時(shí)執行數據庫查詢(xún)。該視圖可以從緩存里檢索而不是重新從控制器行為里生成。緩存讓你避免了服務(wù)器端冗余的工作。
你可以通過(guò)添加一個(gè)[OutputCache]屬性到一個(gè)單獨的控制器行為或一整個(gè)控制器類(lèi)。例如,清單1的控制器暴露了一個(gè)名叫Index()的行為。Index()行為的輸出被緩存10秒。
清單1 - Controllers\HomeController.cs
using System.Web.Mvc;
namespace MvcApplication1.Controllers
{
[HandleError]
public class HomeController : Controller
{
[OutputCache(Duration=10, VaryByParam="none")]
public ActionResult Index()
{
return View();
}
}
}
在A(yíng)SP.NET MVC的Beta版,輸出緩存在這種URL"http://www.MySite.com/"不會(huì )正常工作。相反,你必須輸入一個(gè)像"http://www.MySite.com/Home/Index"這樣的URL。
在清單1,Index()行為的輸出被緩存了10秒。如果你喜歡,你也指定一個(gè)比較長(cháng)的緩存周期。例如,如果你想要緩存一個(gè)控制器行為的輸出一天,那么你可以指定緩存周期為86400秒(60秒×60分×24小時(shí))。
沒(méi)有誰(shuí)保證內容就會(huì )按你指定的時(shí)間緩存那么久。當內存資源變低的時(shí)候,緩存會(huì )自動(dòng)地驅逐內容。
清單1的Home控制器返回了清單2里的Index視圖。這個(gè)視圖沒(méi)有什么特別的。Index視圖簡(jiǎn)單地顯示了當前的時(shí)間(如圖1)。
清單2 - Views\Home\Index.aspx
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Index.aspx.cs" Inherits="MvcApplication1.Views.Home.Index" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Index</title>
</head>
<body>
<div> The current time is: <%= DateTime.Now.ToString("T") %> </div>
</body>
</html>
圖1 - Cached Index view

如果你通過(guò)輸入URL Home/Index到地址欄然后在瀏覽器里重復地單擊刷新按鈕來(lái)調用Index()行為,那么Index視圖里顯示的時(shí)間將在10秒鐘內不會(huì )改變。由于視圖被緩存了,相同的時(shí)間總是被顯示。
相同的視圖是被緩存給每一個(gè)訪(fǎng)問(wèn)你應用的訪(fǎng)客是很重要的。任何調用Index()行為的人都將會(huì )得到相同緩存版本的Index視圖。這意味著(zhù)Web服務(wù)器需要服務(wù)Index視圖的總工作量顯著(zhù)地被減少了。
清單2的視圖恰巧是做一些非常簡(jiǎn)單的事情。這個(gè)視圖只是顯示了當前的時(shí)間。然而,你可以也像這樣簡(jiǎn)單地緩存顯示數據庫記錄的記錄集。在這種情況下,每一次返回視圖的行為控制器被調用時(shí),數據庫記錄不再需要從數據庫檢索。緩存可以降低你的Web服務(wù)器和數據庫服務(wù)器需要執行的工作量。
不要在一個(gè)MVC視圖里使用頁(yè)面指令<%@ OutputCache %>。這條該死的指令來(lái)自Web Forms世界因而不應該在一個(gè)ASP.NET MVC應用里使用。
默認情況下,在你使用[OutputCache]屬性的時(shí)候,內容被緩存在三個(gè)地方:Web服務(wù)器、代理服務(wù)器和瀏覽器。你可以通過(guò)修改[OutputCache]屬性(attribute)的Location屬性精確地控制內容緩存的地方。
你可以設置Location屬性為下面的任意值:
默認情況下,Location屬性的值是Any。然而,存在你只想緩存到瀏覽器或服務(wù)器的情況。舉例來(lái)說(shuō),如果你想緩存每個(gè)用戶(hù)個(gè)性化的信息,那么就不應該緩存信息到服務(wù)器。如果你想顯示不同的信息到不同的用戶(hù)那么你應該緩存信息到客戶(hù)端。
例如,清單3的控制器暴露了一個(gè)名叫GetName()的返回當前用戶(hù)名字的行為。如果Jack登錄了該網(wǎng)站然后調用了GetName()行為那么該行為返回字符串"Hi Jack"。如果,隨后,Jill登錄了該網(wǎng)站然后調用了GetName()行為那么她也會(huì )獲得同樣的字符串"Hi Jack"。這個(gè)字符串在Jack最初調用控制器行為的時(shí)候被緩存在Web服務(wù)器給所有的用戶(hù)
清單3 - Controllers\BadUserController.cs
using System.Web.Mvc;
using System.Web.UI;
namespace MvcApplication1.Controllers
{
public class BadUserController : Controller
{
[OutputCache(Duration = 3600, VaryByParam = "none")]
public string GetName()
{
return "Hi " + User.Identity.Name;
}
}
}
最有可能的是,清單3的控制器不像你想的那樣工作。你不會(huì )想顯示"Hi Jack"給Jilll。
你永遠都不應該在服務(wù)器緩存里緩存個(gè)性化內容。但你可能想要在瀏覽器緩存里緩存個(gè)性化的內容來(lái)提升性能。如果你在瀏覽器端緩存內容,并且一個(gè)用戶(hù)調用幾次了同樣的控制器行為,那么該緩存內容可以從瀏覽器緩存檢索到而不是從服務(wù)器端緩存檢索。
清單4修改過(guò)的控制器緩存了GetName()行為的輸出。但是,這些內容僅僅被緩存到瀏覽器端而不是服務(wù)器端。通過(guò)這種方式,在多個(gè)用戶(hù)調用GetName()方法的時(shí)候,每個(gè)人得到他們自己的名字而不是其他用戶(hù)的用戶(hù)名。
清單4 - Controllers\UserController.cs
using System.Web.Mvc;
using System.Web.UI;
namespace MvcApplication1.Controllers
{
public class UserController : Controller
{
[OutputCache(Duration=3600, VaryByParam="none", Location=OutputCacheLocation.Client, NoStore=true)]
public string GetName()
{
return "Hi " + User.Identity.Name;
}
}
}
注意清單4的[OutputCache]屬性包含了一個(gè)值設為OutputCacheLocation.Clientd的Location屬性。[OutputCache]屬性頁(yè)包含了一個(gè)NoStore屬性。NoStore屬性被用來(lái)通知代理服務(wù)器和瀏覽器它們不應該緩存一個(gè)永久的緩存內容的拷貝。
在一些情形下,你可能想要不同緩存版本的非常相似的內容。想象一下,你正在創(chuàng )建一個(gè)母版/詳細頁(yè)面。母版頁(yè)沒(méi)顯示一個(gè)電影標題的列表。當你點(diǎn)擊一個(gè)標題,你會(huì )得到選擇到的電影的具體內容。
如果你緩存詳細頁(yè)面,那么無(wú)論你點(diǎn)擊哪個(gè)電影標題,都只會(huì )顯示同一個(gè)電影的具體內容。第一個(gè)用戶(hù)選擇的第一個(gè)電影會(huì )被顯示給所有的用戶(hù)。
利用[OutputCache]屬性的VaryByParam屬性你可以修復這個(gè)問(wèn)題。這個(gè)屬性允許你在表單參數或查詢(xún)字符串參數不同的時(shí)候創(chuàng )建具有非常相似內容的不同緩存的版本。
例如,清單5的控制器暴露了兩個(gè)名叫Master()和Detials()的行為。Master()行為返回了一個(gè)電影標題的列表而Detail()行為返回了被選中的電影的具體信息。
清單5 - Controllers\MoviesController.cs
using System.Linq;
using System.Web.Mvc;
using MvcApplication1.Models;
namespace MvcApplication1.Controllers
{
public class MoviesController : Controller
{
private MovieDataContext _dataContext;
public MoviesController()
{
_dataContext = new MovieDataContext();
}
[OutputCache(Duration=int.MaxValue, VaryByParam="none")]
public ActionResult Master()
{
ViewData.Model = (from m in _dataContext.Movies
select m).ToList();
return View();
}
[OutputCache(Duration = int.MaxValue, VaryByParam = "id")]
public ActionResult Details(int id)
{
ViewData.Model = _dataContext.Movies.SingleOrDefault(m => m.Id == id);
return View();
}
}
}
Master()行為包含了一個(gè)值為"none"的VaryByParam屬性。在Master()行為被調用的時(shí)候,相同緩存版本的Master視圖被返回。任何參數或查詢(xún)字符傳參數都被忽略(如圖2)。
圖2 - The /Movies/Master view

圖3 - The /Movies/Details view

Details()行為包含了值為"Id"的VaryByParam屬性。在不同的Id參數的值被傳入到控制器行為后,緩存的不同版本的Details視圖被生成了。
很重要的一點(diǎn)就是要理解使用VaryByParam屬性的后果是使用更多的緩存而不是更少。不同版本的緩存在Details視圖中不同版本的Id參數被傳入后被創(chuàng )建。
你可以將VaryByParam屬性設置成下列的值:
* =在表單的參數或查詢(xún)字符串參數不同的時(shí)候創(chuàng )建一個(gè)不同版本的緩存。
none = 從不創(chuàng )建不同版本的緩存。
以分號分割的參數列表=在列表的任何表單或查詢(xún)字符串參數不同的時(shí)候創(chuàng )建不同的緩存版本。
作為修改[OutputCache]屬性(attribute)的屬性(properties)另外一種配置輸出緩存屬性的可選方法,你可以在Web配置文件(Web.config)里創(chuàng )建一個(gè)緩存文件。在Web配置文件里創(chuàng )建一個(gè)緩存文件為你提供了一系列的重要的好處。
第一,通過(guò)在Web配置文件配置輸出緩存,你可以控制控制器如何在一個(gè)中心的位置緩存內容。你可以創(chuàng )建一個(gè)緩存文件然后將該文件應用到幾個(gè)控制器或控制器行為。
第二,你可以修改Web配置文件而不用重編譯你的應用。如果你需要禁用一個(gè)已經(jīng)部署到生產(chǎn)的應用的緩存,那么你可以簡(jiǎn)單地修改定義在Web配置文件的緩存文件。任何Web配置文件的改變都會(huì )被自動(dòng)地檢測并被應用。
例如,清單6的<caching>web配置節點(diǎn)定義了一個(gè)名叫Cache1Hour的緩存文件。<caching>節點(diǎn)必須和<system.web>節點(diǎn)一起出現在一個(gè)web配置文件。
清單6 - Caching section for web.config
<caching>
<outputCacheSettings>
<outputCacheProfiles>
<add name="Cache1Hour" duration="3600" varyByParam="none"/>
</outputCacheProfiles>
</outputCacheSettings>
</caching>
清單7的控制器描述了利用[OutpucCache]屬性你可以怎樣使用將Cache1Hour profile應用到一個(gè)控制器行為。
清單7 - Controllers\ProfileController.cs
using System;
using System.Web.Mvc;
namespace MvcApplication1.Controllers
{
public class ProfileController : Controller
{
[OutputCache(CacheProfile="Cache1Hour")]
public string Index()
{
return DateTime.Now.ToString("T");
}
}
}
如果你想調用在清單7里的控制器暴露的Index()行為,那么相同的時(shí)間會(huì )被返回一個(gè)小時(shí)之久。
輸出緩存提供給了你一個(gè)非常簡(jiǎn)單的方式來(lái)顯著(zhù)提高你的ASP.NET MVC應用的性能。在這篇教程里,你學(xué)習了如何使用[OutputCache]屬性來(lái)緩存控制器行為的輸出。你也學(xué)習了如何修改[OutputCache]里諸如Duration和VaryByParam屬性來(lái)修改內容是如何被緩存的。最后,你學(xué)習了如何在web配置文件定義緩存文件。
聯(lián)系客服
微信登錄中...
請勿關(guān)閉此頁(yè)面
