使用輸出快取改善效能 (C#)

Microsoft

在本教學課程中,您將瞭解如何利用輸出快取來大幅提升 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–快取索引視圖

clip_image002

如果您藉由在瀏覽器的網址列中輸入 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

clip_image004

圖3–/Movies/Details view

clip_image006

詳細資料 () 動作包含值為 "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 設定檔中定義快取設定檔。