使用輸出快取改善效能 (C#)
在本教學課程中,您將瞭解如何利用輸出快取來大幅提升 ASP.NET MVC web 應用程式的效能。 您將瞭解如何快取從控制器動作傳回的結果,如此一來,每次新的使用者叫用該動作時,都不需要建立相同的內容。
本教學課程的目的是要說明如何利用輸出快取來大幅提升 ASP.NET MVC 應用程式的效能。 輸出快取可讓您快取控制器動作所傳回的內容。 如此一來,每次叫用相同的控制器動作時,都不需要產生相同的內容。
例如,Imagine 您的 ASP.NET MVC 應用程式會在名為 Index 的 view 中顯示資料庫記錄清單。 一般情況下,每次使用者叫用傳回索引視圖的控制器動作時,都必須藉由執行資料庫查詢,從資料庫中取出資料庫記錄集。
另一方面,如果您利用輸出快取,就可以避免每次使用者叫用相同的控制器動作時執行資料庫查詢。 您可以從快取中取出此視圖,而不是從控制器動作重新產生。 快取可讓您避免在伺服器上執行重複的工作。
啟用輸出快取
您可以將 [OutputCache] 屬性新增至個別控制器動作或整個控制器類別,藉以啟用輸出快取。 例如,[清單 1] 中的控制器會公開名為 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();
}
}
}
在 ASP.NET MVC 的 Beta 版中,輸出快取無法針對像這樣 http://www.MySite.com/ 的 URL 運作。 相反地,您必須輸入類似 http://www.MySite.com/Home/Index 的 URL。
在 [清單 1] 中,索引的輸出 () 動作會快取10秒。 如果您想要的話,可以指定較長的快取持續時間。 例如,如果您想要快取一天的控制器動作輸出,則可以指定86400秒的快取持續時間 (60 秒 * 60 分鐘 * 24 小時) 。
不保證會在您指定的時間量內快取內容。 當記憶體資源過低時,快取會自動開始自動收回內容。
[清單 1] 中的 Home 控制器會傳回 [清單 2] 中的索引視圖。 此視圖沒有任何特殊之處。 索引視圖只會顯示目前的時間 (請參閱 [圖 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–快取索引視圖
如果您藉由在瀏覽器的網址列中輸入 URL/Home/Index 來多次叫用索引 () 動作,然後重複使用瀏覽器中的重新整理/重載按鈕,則索引視圖所顯示的時間不會變更10秒。 因為快取視圖,所以會顯示相同的時間。
請務必瞭解,針對造訪您應用程式的每個人都會快取相同的視圖。 任何叫用索引 () 動作的人都會取得相同的快取版本的索引視圖。 這表示,web 伺服器為了提供索引視圖而必須執行的工作量會大幅降低。
在 [清單 2] 中的觀點,其實很簡單。 此視圖只會顯示目前的時間。 不過,您可以輕鬆地快取顯示一組資料庫記錄的視圖。 在這種情況下,每次叫用傳回 view 的控制器動作時,都不需要從資料庫中取出資料庫記錄集。 快取可以減少 web 伺服器和資料庫伺服器必須執行的工作量。
請勿在 MVC 視圖中使用頁面 < % @ OutputCache% > 指示詞。 這個指示詞在 Web Form 的世界中是一項不規則的,不應該用於 ASP.NET MVC 應用程式。
快取內容的位置
依預設,當您使用 [OutputCache] 屬性時,會在三個位置中快取內容:網頁伺服器、任何 proxy 伺服器和網頁瀏覽器。 您可以藉由修改 [OutputCache] 屬性的 Location 屬性,精確控制內容的快取位置。
您可以將 Location 屬性設定為下列其中一個值:
·任何
·客戶
·下游
·伺服器
·沒有
·ServerAndClient
依預設,Location 屬性的值為 Any。 不過,在某些情況下,您可能只想要在瀏覽器上或只在伺服器上快取。 例如,如果您要快取為每位使用者個人化的資訊,則您不應該快取伺服器上的資訊。 如果您要向不同的使用者顯示不同的資訊,則應該只在用戶端上快取資訊。
例如,[清單 3] 中的控制器會公開一個名為 GetName () 的動作,以傳回目前的使用者名稱。 如果您在網站中登入,並叫用 GetName () 動作,則該動作會傳回字串 "Hi"。 如果之後 Jill 登入網站,並叫用 GetName () 動作,則她也會取得字串 "Hi"。 當插孔一開始叫用控制器動作時,會在 web 伺服器上為所有使用者快取字串。
清單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中的控制器無法以您想要的方式運作。 您不想要在 Jill 中顯示「Hi」訊息。
您永遠不應該在伺服器快取中快取個人化內容。 不過,您可能會想要快取瀏覽器快取中的個人化內容,以改善效能。 如果您在瀏覽器中快取內容,且使用者多次叫用相同的控制器動作,則可以從瀏覽器快取(而非伺服器)抓取內容。
[清單 4] 中修改過的控制器會快取 GetName () 動作的輸出。 不過,只會在瀏覽器上快取內容,而不是在伺服器上快取。 如此一來,當多位使用者叫用 GetName () 方法時,每個人都會取得自己的使用者名稱,而不是另一個人的使用者名稱。
清單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] 屬性包含設定為值 OutputCacheLocation 的 Location 屬性。 [OutputCache] 屬性也包含 NoStore 屬性。 NoStore 屬性是用來通知 proxy 伺服器和瀏覽器,不應儲存快取內容的永久複本。
改變輸出快取
在某些情況下,您可能會想要有相同內容的不同快取版本。 例如,您要建立主版/詳細資料頁面的 Imagine。 主版頁面會顯示電影標題的清單。 當您按一下標題時,會取得所選電影的詳細資料。
如果您快取 [詳細資料] 頁面,就會顯示相同電影的詳細資料,無論您按一下哪個電影。 第一個使用者選取的第一個電影將會顯示給所有未來的使用者。
您可以利用 [OutputCache] 屬性的 VaryByParam 屬性來修正這個問題。 這個屬性可讓您在表單參數或查詢字串參數有所差異時,為相同的內容建立不同的快取版本。
例如,清單5中的控制器會公開兩個名為 Master () 的動作,以及 () 的詳細資料。 主要 () 動作會傳回電影標題清單和詳細資料 () 動作會傳回所選電影的詳細資料。
清單 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();
}
}
}
主要 () 動作包含值為 "none" 的 VaryByParam 屬性。 叫用主要 () 動作時,會傳回相同的主視圖快取版本。 系統會忽略任何表單參數或查詢字串參數 (請參閱 [圖 2]) 。
圖 2-/Movies/Master view
圖3–/Movies/Details view
詳細資料 () 動作包含值為 "Id" 的 VaryByParam 屬性。 當識別碼參數的不同值傳遞至控制器動作時,會產生詳細資料檢視的不同快取版本。
請務必瞭解,使用 VaryByParam 屬性會產生更快的快取,而不會減少。 針對每個不同版本的 Id 參數,會建立不同的快取版本的詳細資料檢視。
您可以將 VaryByParam 屬性設定為下列值:
* = 當表單或查詢字串參數不同時,建立不同的快取版本。
none = 永不建立不同的快取版本
如果清單中的任何表單或查詢字串參數有變化,則參數的分號清單會建立不同的快取版本
建立快取設定檔
除了透過修改 [OutputCache] 屬性的屬性來設定輸出快取屬性之外,您還可以在 web 設定 (web.config) 檔中建立快取設定檔。 在 web 設定檔中建立快取設定檔提供幾個重要的優點。
首先,藉由在 web 設定檔中設定輸出快取,您可以控制控制器動作如何在一個集中位置快取內容。 您可以建立一個快取設定檔,並將設定檔套用至數個控制器或控制器動作。
其次,您可以修改 web 設定檔,而不需要重新編譯您的應用程式。 如果您需要針對已部署至生產環境的應用程式停用快取,您可以直接修改 web 設定檔中定義的快取設定檔。 系統會自動偵測並套用對 web 設定檔進行的任何變更。
例如,[清單 6] 中的 [ <> 快取] web 設定區段會定義名為 Cache1Hour 的快取設定檔。 >[ < 快取] 區段必須出現在 web 設定檔的 [ < web > ] 區段中。
清單6– web.config的快取區段
<caching>
<outputCacheSettings>
<outputCacheProfiles>
<add name="Cache1Hour" duration="3600" varyByParam="none"/>
</outputCacheProfiles>
</outputCacheSettings>
</caching>
[清單 7] 中的控制器說明如何使用 [OutputCache] 屬性將 Cache1Hour 設定檔套用至控制器動作。
清單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] 中叫用控制器所公開的索引 () 動作,則會傳回1小時的相同時間。
總結
輸出快取提供一種非常簡單的方法,可大幅提升 ASP.NET MVC 應用程式的效能。 在本教學課程中,您已瞭解如何使用 [OutputCache] 屬性來快取控制器動作的輸出。 您也已瞭解如何修改 [OutputCache] 屬性的屬性,例如 Duration 和 VaryByParam 屬性,以修改內容的快取方式。 最後,您已瞭解如何在 web 設定檔中定義快取設定檔。