Share via


在應用程式啟動時快取資料 (C#)

作者:Scott Mitchell

下載 PDF

在任何 Web 應用程式中,都會經常使用某些數據,而某些數據則不常使用。 我們可以藉由預先載入常用數據,也就是稱為快取的技術,來改善 ASP.NET 應用程式的效能。 本教學課程示範主動式載入的一種方法,也就是在應用程式啟動時將數據載入快取。

簡介

前兩個教學課程探討在簡報和快取層中快取數據。 在 使用 ObjectDataSource 快取數據中,我們已探討如何使用 ObjectDataSource 的快取功能來快取呈現層中的數據。 在架構中 快取數據會檢查新、個別快取層中的快取。 這兩個教學課程都使用 回應式載入 來處理數據快取。 透過回應式載入,每次要求數據時,系統會先檢查它是否在快取中。 如果沒有,它會從原始來源擷取數據,例如資料庫,然後將它儲存在快取中。 回應式載入的主要優點是其易於實作。 其缺點之一是其跨要求的效能不平均。 假設有一個頁面使用上述教學課程中的快取層來顯示產品資訊。 當第一次流覽此頁面,或第一次在快取的數據因記憶體限制或已達到指定的到期而收回之後,必須從資料庫擷取數據。 因此,這些使用者要求所需的時間會比快取可提供服務的使用者要求還要長。

主動式載入 提供替代的快取管理策略,可藉由在需要之前載入快取的數據,以達到跨要求的效能。 一般而言,主動式載入會使用一些程式,在基礎數據更新時定期檢查或收到通知。 接著,此程式會更新快取,使其保持最新狀態。 如果基礎數據來自緩慢的資料庫連線、Web 服務或其他一些特別緩慢的數據源,主動式載入特別有用。 但是,主動式載入的此方法較難以實作,因為它需要建立、管理及部署程式,以檢查變更並更新快取。

另一種主動式載入,以及我們將在本教學課程中探索的類型,是在應用程式啟動時將數據載入快取中。 此方法特別適用於快取靜態數據,例如資料庫查閱數據表中的記錄。

注意

For a more in-depth look at the differences between proactive and reactive loading, as well as lists of pros, cons, and implementation recommendations, refer to the Managing the Contents of a Cache section of the Caching Architecture Guide for .NET Framework Applications.

步驟 1:決定應用程式啟動時要快取的數據

使用我們在前兩個教學課程中檢查的回應式載入,快取範例適用於可能會定期變更的數據,而且不會產生非常長的時間。 但是,如果快取的數據永遠不會變更,則回應式載入所使用的過期是多餘的。 同樣地,如果快取的數據需要很長的時間才能產生,則要求尋找空白快取的用戶必須在擷取基礎數據時產生冗長的等候。 請考慮快取在應用程式啟動時產生非常長時間的靜態數據和數據。

雖然資料庫有許多動態且經常變更的值,但大部分的靜態數據也有相當大量的靜態數據。 例如,幾乎所有數據模型都有一或多個數據行,其中包含一組固定選項中的特定值。 Patients資料庫數據表可能有一個PrimaryLanguage數據行,其值集可以是英文、西班牙文、法文、俄文、日文等等。 通常,這些類型的數據行是使用 查閱數據表來實作。 除了將字串英文或法文儲存在數據表中 Patients ,而是建立第二個數據表,通常有兩個數據行 -唯一標識符和字串描述,每個可能值的記錄。 數據表 PrimaryLanguage 中的數據 Patients 行會將對應的唯一標識符儲存在查閱表格中。 在圖 1 中,病患 John Doe 的主要語言是英文,而 Ed John Doe 是俄文。

語言數據表是病患數據表所使用的查閱表格

圖 1:數據表 Languages 是數據表所使用的 Patients 查閱表格

編輯或建立新病患的使用者介面會包含數據表中 Languages 記錄所填入允許語言的下拉式清單。 如果沒有快取,每次流覽此介面時,系統都必須查詢 Languages 數據表。 這很浪費,而且不必要,因為查閱表格值在常數不常變更。

我們可以使用先前教學課程中檢查的相同回應式載入技術來快取 Languages 數據。 不過,回應式載入會使用以時間為基礎的到期,這不需要靜態查閱數據表數據。 雖然使用回應式載入的快取比完全不快取更好,但最佳方法是在應用程式啟動時主動將查閱表數據載入快取。

在本教學課程中,我們將探討如何快取查閱表格數據和其他靜態資訊。

步驟 2:檢查快取數據的不同方式

資訊可以使用各種方法,以程序設計方式在 ASP.NET 應用程式中快取。 我們已瞭解如何在先前的教學課程中使用數據快取。 或者,您可以使用 靜態成員應用程式狀態,以程序設計方式快取物件。

使用類別時,通常必須先具現化類別,才能存取其成員。 例如,為了從商業規則層的其中一個類別叫用方法,我們必須先建立 類別的實例:

ProductsBLL productsAPI = new ProductsBLL();
productsAPI.SomeMethod();
productsAPI.SomeProperty = "Hello, World!";

在我們可以叫用 SomeMethod 或使用 SomeProperty 之前,我們必須先使用 new 關鍵詞來建立 類別的實例。 SomeMethodSomeProperty 與特定實例相關聯。 這些成員的存留期會系結至其相關聯物件的存留期。 另一方面,靜態成員是類別的所有實例之間共用的變數、屬性和方法,因此只要類別,就會有存留期。 靜態成員是由 關鍵詞 static表示。

除了靜態成員之外,也可以使用應用程式狀態來快取數據。 每個 ASP.NET 應用程式都會維護跨應用程式所有用戶和頁面共用的名稱/值集合。 您可以使用 類別Application 屬性來存取HttpContext此集合,並從 ASP.NET 頁面的程式代碼後置類別使用,如下所示:

Application["key"] = value;
object value = Application["key"];

數據快取提供更豐富的 API 來快取數據,並提供時間與相依性型到期、快取專案優先順序等機制。 使用靜態成員和應用程式狀態時,頁面開發人員必須手動新增這類功能。 不過,在應用程式啟動時快取數據時,數據快取的優點是無問題。 在本教學課程中,我們將探討使用這三種技術來快取靜態數據的程序代碼。

步驟 3:快取Suppliers數據表數據

我們實作到最新狀態的 Northwind 資料庫數據表不包含任何傳統的查閱數據表。 在 DAL 中實作的四個 DataTable 都是非靜態值的所有模型數據表。 在本教學課程中,我們只是假設數據表的數據是靜態的,而不是花費時間將新的 DataTable 新增至 DAL,然後將新的類別和方法新增 Suppliers 至 BLL。 因此,我們可以在應用程式啟動時快取此數據。

若要開始,請在資料夾中建立名為 StaticCache.csCL 的新類別。

在 CL 資料夾中建立StaticCache.cs類別

圖 2:在CL資料夾中建立 StaticCache.cs 類別

我們需要新增方法,以在啟動時將數據載入適當的快取存放區,以及從這個快取傳回數據的方法。

[System.ComponentModel.DataObject]
public class StaticCache
{
    private static Northwind.SuppliersDataTable suppliers = null;
    public static void LoadStaticCache()
    {
        // Get suppliers - cache using a static member variable
        SuppliersBLL suppliersBLL = new SuppliersBLL();
        suppliers = suppliersBLL.GetSuppliers();
    }
    [DataObjectMethodAttribute(DataObjectMethodType.Select, true)]
    public static Northwind.SuppliersDataTable GetSuppliers()
    {
        return suppliers;
    }
}

上述程式代碼會使用靜態成員變數suppliers來保存類別GetSuppliers()的方法結果SuppliersBLL,其會從 LoadStaticCache() 方法呼叫。 方法 LoadStaticCache() 是要在應用程式啟動時呼叫。 在應用程式啟動時載入此數據之後,任何需要與供應商數據搭配運作的頁面都可以呼叫 StaticCache 類別 GetSuppliers() 的方法。 因此,在應用程式啟動時,呼叫資料庫以取得供應商只會發生一次。

我們可以使用應用程式狀態或數據快取,而不是使用靜態成員變數作為快取存放區。 下列程式代碼顯示已重新設定為使用應用程式狀態的類別:

[System.ComponentModel.DataObject]
public class StaticCache
{
    public static void LoadStaticCache()
    {
        // Get suppliers - cache using application state
        SuppliersBLL suppliersBLL = new SuppliersBLL();
        HttpContext.Current.Application["key"] = suppliersBLL.GetSuppliers();
    }
    [DataObjectMethodAttribute(DataObjectMethodType.Select, true)]
    public static Northwind.SuppliersDataTable GetSuppliers()
    {
        return HttpContext.Current.Application["key"] as Northwind.SuppliersDataTable;
    }
}

LoadStaticCache()中,供應商資訊會儲存至應用程式變數 金鑰。 它會從傳回為適當的類型 (Northwind.SuppliersDataTable) GetSuppliers()。 雖然應用程式狀態可以在使用 Application["key"]ASP.NET 頁面的程式代碼後置類別中存取,但在此架構中,我們必須使用 HttpContext.Current.Application["key"] ,才能取得目前的 HttpContext

同樣地,數據快取可以當做快取存放區使用,如下列程式代碼所示:

[System.ComponentModel.DataObject]
public class StaticCache
{
    public static void LoadStaticCache()
    {
        // Get suppliers - cache using the data cache
        SuppliersBLL suppliersBLL = new SuppliersBLL();
        HttpRuntime.Cache.Insert(
          /* key */                "key", 
          /* value */              suppliers, 
          /* dependencies */       null, 
          /* absoluteExpiration */ Cache.NoAbsoluteExpiration, 
          /* slidingExpiration */  Cache.NoSlidingExpiration, 
          /* priority */           CacheItemPriority.NotRemovable, 
          /* onRemoveCallback */   null);
    }
    [DataObjectMethodAttribute(DataObjectMethodType.Select, true)]
    public static Northwind.SuppliersDataTable GetSuppliers()
    {
        return HttpRuntime.Cache["key"] as Northwind.SuppliersDataTable;
    }
}

若要將專案新增至沒有以時間為基礎的到期時間的數據快取,請使用 System.Web.Caching.Cache.NoAbsoluteExpirationSystem.Web.Caching.Cache.NoSlidingExpiration 值作為輸入參數。 已選取此數據快取 Insert 方法的特定多載,以便我們可以指定快取專案的 優先順序 。 優先順序是用來判斷當可用記憶體不足時,要從快取中擷取的專案。 在這裡,我們會使用優先順序 NotRemovable,以確保不會清除此快取專案。

注意

本教學課程的下載會使用靜態成員變數方法實 StaticCache 作 類別。 應用程式狀態和數據快取技術的程式代碼可在類別檔案中的批注中使用。

步驟 4:在應用程式啟動時執行程序代碼

若要在 Web 應用程式第一次啟動時執行程式代碼,我們需要建立名為 Global.asax的特殊檔案。 此檔案可以包含應用程式層級事件、會話和要求層級事件的事件處理程式,在此,我們可以在此新增每當應用程式啟動時執行的程序代碼。

Global.asax以滑鼠右鍵按兩下 Visual Studio 方案總管 中的網站專案名稱,然後選擇 [新增專案],將檔案新增至 Web 應用程式的根目錄。 從 [新增專案] 對話框中,選取 [全域應用程式類別] 專案類型,然後按兩下 [新增] 按鈕。

注意

如果您的項目中已經有檔案 Global.asax ,[全域應用程式類別] 項目類型將不會列在 [新增專案] 對話框中。

將 Global.asax 檔案新增至 Web 應用程式的根目錄

圖 3:將 Global.asax 檔案新增至 Web 應用程式的根目錄 (按兩下以檢視完整大小的映像)

預設 Global.asax 檔案範本包含伺服器端 <script> 標籤的五種方法:

  • Application_Start 會在 Web 應用程式第一次啟動時執行
  • Application_End 在應用程式關閉時執行
  • Application_Error 每當未處理的例外狀況到達應用程式時,就會執行
  • Session_Start 在建立新的工作階段時執行
  • Session_End 會話過期或放棄時執行

Application_Start事件處理程式只會在應用程式的生命週期中呼叫一次。 應用程式第一次從應用程式要求 ASP.NET 資源,並繼續執行,直到應用程式重新啟動為止,這可能會因為修改資料夾的內容、修改 Global.asax、修改資料夾中的內容/BinApp_Code或修改Web.config檔案,以及其他原因而發生。 如需應用程式生命週期的詳細討論 ,請參閱 ASP.NET 應用程式生命週期概觀

針對這些教學課程,我們只需要將程式代碼新增至 Application_Start 方法,因此請隨意移除其他教學課程。 在 中 Application_Start,只要呼叫 StaticCache 類別 LoadStaticCache() 的 方法,它會載入並快取供應商資訊:

<%@ Application Language="C#" %>
<script runat="server">
    void Application_Start(object sender, EventArgs e) 
    {
        StaticCache.LoadStaticCache();
    }
</script>

就是這麼簡單! 在應用程式啟動時, LoadStaticCache() 此方法會從 BLL 擷取供應商資訊,並將它儲存在靜態成員變數 (,或您最後在類別中使用 StaticCache 的任何快取存放區) 。 若要確認此行為,請在 Application_Start 方法中設定斷點並執行您的應用程式。 請注意,斷點會在應用程式啟動時叫用。 不過,後續的要求不會造成 Application_Start 方法執行。

使用斷點確認正在執行Application_Start事件處理程式

圖 4:使用斷點確認 Application_Start 事件處理程式正在執行 (按兩下以檢視完整大小的映像)

注意

如果您第一次開始偵錯時未叫用 Application_Start 斷點,這是因為您的應用程式已經啟動。 藉由修改 或 Global.asaxWeb.config 檔案來強制應用程式重新啟動,然後再試一次。 您可以直接新增 (或移除) 其中一個檔案結尾的空白行,以快速重新啟動應用程式。

步驟 5:顯示快取的數據

此時,類別 StaticCache 具有在應用程式啟動時快取的供應商數據版本,可透過其 GetSuppliers() 方法存取。 若要從簡報層使用此數據,我們可以使用 ObjectDataSource,或以程式設計方式從 ASP.NET 頁面的程式代碼後置類別叫 StaticCache 用 類別 GetSuppliers() 的 方法。 讓我們看看如何使用 ObjectDataSource 和 GridView 控件來顯示快取的供應商資訊。

首先, AtApplicationStartup.aspx 開啟資料夾中的頁面 Caching 。 將 GridView 從 [工具箱] 拖曳至設計工具,並將其 ID 屬性設定為 Suppliers。 接下來,從 GridView 的智慧標記選擇建立名為 SuppliersCachedDataSource的新 ObjectDataSource。 將 ObjectDataSource 設定為使用 StaticCache 類別的 GetSuppliers() 方法。

設定 ObjectDataSource 以使用 StaticCache 類別

圖 5:設定 ObjectDataSource 以使用 StaticCache 類別 (按鍵即可檢視大小完整的映射)

使用 GetSuppliers () 方法來擷取快取的供應商數據

圖 6:使用 GetSuppliers() 方法來擷取快取的供應商數據 (按兩下即可檢視大小完整的影像)

完成精靈之後,Visual Studio 會自動為 中的每個 SuppliersDataTable數據欄位新增 BoundFields。 您的 GridView 和 ObjectDataSource 宣告式標記看起來應該類似下列內容:

<asp:GridView ID="Suppliers" runat="server" AutoGenerateColumns="False" 
    DataKeyNames="SupplierID" DataSourceID="SuppliersCachedDataSource" 
    EnableViewState="False">
    <Columns>
        <asp:BoundField DataField="SupplierID" HeaderText="SupplierID" 
            InsertVisible="False" ReadOnly="True" 
            SortExpression="SupplierID" />
        <asp:BoundField DataField="CompanyName" HeaderText="CompanyName" 
            SortExpression="CompanyName" />
        <asp:BoundField DataField="Address" HeaderText="Address" 
            SortExpression="Address" />
        <asp:BoundField DataField="City" HeaderText="City" 
            SortExpression="City" />
        <asp:BoundField DataField="Country" HeaderText="Country" 
            SortExpression="Country" />
        <asp:BoundField DataField="Phone" HeaderText="Phone" 
            SortExpression="Phone" />
    </Columns>
</asp:GridView>
<asp:ObjectDataSource ID="SuppliersCachedDataSource" runat="server" 
    OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetSuppliers" TypeName="StaticCache" />

圖 7 顯示透過瀏覽器檢視時的頁面。 輸出與從 BLL 類別 SuppliersBLL 提取資料相同,但使用 StaticCache 類別會傳回在應用程式啟動時快取的供應商數據。 您可以在 類別GetSuppliers()的 方法中StaticCache設定斷點,以確認此行為。

快取的供應商數據會顯示在 GridView 中

圖 7:快取的供應商數據會顯示在 GridView (按兩下即可檢視大小完整的影像)

摘要

大部分的數據模型都包含相當大量的靜態數據,通常是以查閱表格的形式實作。 由於這項資訊是靜態的,因此每次需要顯示此資訊時,都不需要持續存取資料庫。 此外,由於靜態本質,在快取數據時不需要到期。 在本教學課程中,我們已瞭解如何採用這類數據,並將其快取在數據快取、應用程式狀態,以及透過靜態成員變數快取。 此資訊會在應用程式啟動時快取,並在整個應用程式的存留期內保留在快取中。

在本教學課程和過去兩個教學課程中,我們已查看應用程式存留期的快取數據,以及使用以時間為基礎的到期日。 不過,快取資料庫數據時,以時間為基礎的到期時間可能小於理想。 相較於定期排清快取,最好只在修改基礎資料庫數據時收回快取的專案。 此理想做法是透過使用 SQL 快取相依性,我們將在下一個教學課程中加以檢查。

快樂的程序設計!

關於作者

Scott Mitchell 是七份 ASP/ASP.NET 書籍的作者,以及 1998 年以來與 Microsoft Web 技術合作的 4GuysFromRolla.com 作者。 Scott 是獨立顧問、訓練員和作者。 他的最新書籍是 Sams 在 24 小時內自行 ASP.NET 2.0。 您可以透過mitchell@4GuysFromRolla.com部落格來連線到 ,您可以在 找到http://ScottOnWriting.NET

特別感謝

本教學課程系列是由許多實用的檢閱者檢閱。 本教學課程的首席檢閱者是 Teresa Murphy 和 Zack Jones。 有興趣檢閱即將推出的 MSDN 文章嗎? 如果是,請將一行 mitchell@4GuysFromRolla.com放在 。