首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> ASP.NET 基礎 >> 關於ASP.NET

ASP.NET 2.0 分層架構快取策略:建立獨立快取層 (Caching Layer) 解耦表現層

     編輯:關於ASP.NET

ASP.NET 2.0 ObjectDataSource 內建快取功能雖方便,但將快取邏輯耦合在表現層,違反分層架構原則。本文示範建立獨立 快取層 (Caching Layer, CL),位於表現層與業務邏輯層 (BLL) 之間,統一管理快取策略、相依性、過期政策,實現關注點分離。

架構演進:從表現層快取到獨立快取層

層級傳統 ObjectDataSource 快取獨立快取層 (CL)
快取位置表現層 (ASPX/ObjectDataSource)獨立 CL 類別庫 / App_Code/CL
耦合度緊密耦合頁面生命週期鬆散耦合,可單元測試、可複用
快取策略分散在各頁面宣告集中在 CL 方法內,統一管理
相依性管理較難協調跨頁面相依性集中處理 SqlCacheDependency、檔案相依性
測試性需啟動 Web 伺服器測試純類別庫,易於單元測試

專案結構

MySolution/
├── DAL/                    # Data Access Layer (Typed DataSet / TableAdapter)
├── BLL/                    # Business Logic Layer (ProductsBLL, CategoriesBLL)
├── CL/                     # Caching Layer (新增)
│   ├── ProductsCL.cs
│   ├── CategoriesCL.cs
│   └── SuppliersCL.cs
├── WebApp/                 # Presentation Layer (ASP.NET WebForms / MVC)
│   ├── App_Code/CL/        # 或編譯為獨立 DLL 參考
│   └── ...
└── Tests/                  # Unit Tests (可直接測試 CL)

ProductsCL 核心實作

using System;
using System.Data;
using System.Web.Caching;
using BLL; // 參考業務邏輯層

namespace CL
{
    public class ProductsCL
    {
        private readonly ProductsBLL _bll = new ProductsBLL();
        private const string CacheKeyPrefix = "ProductsCL_";

        /// 
        /// 取得所有產品:優先快取,遺漏則查詢 BLL 並建立快取相依性
        /// 
        public DataTable GetProducts()
        {
            string cacheKey = CacheKeyPrefix + "AllProducts";
            object cached = HttpRuntime.Cache[cacheKey];
            
            if (cached != null)
                return (DataTable)cached;

            // 快取遺漏:呼叫 BLL 取得資料
            DataTable dt = _bll.GetProducts();

            // 建立快取相依性:資料庫變更自動失效 (需 SQL Server 2005+ 啟用 Service Broker)
            // 此處示範檔案相依性,實務建議使用 SqlCacheDependency
            CacheDependency dep = new CacheDependency(null); // 無實體相依性,僅時間過期
            
            HttpRuntime.Cache.Insert(cacheKey, dt, dep, 
                DateTime.Now.AddMinutes(30), Cache.NoSlidingExpiration);
            
            return dt;
        }

        /// 
        /// 依類別編號取得產品
        /// 
        public DataTable GetProductsByCategoryID(int categoryID)
        {
            string cacheKey = $"{CacheKeyPrefix}Cat_{categoryID}";
            object cached = HttpRuntime.Cache[cacheKey];
            if (cached != null) return (DataTable)cached;

            DataTable dt = _bll.GetProductsByCategoryID(categoryID);
            HttpRuntime.Cache.Insert(cacheKey, dt, null, 
                DateTime.Now.AddMinutes(20), Cache.NoSlidingExpiration);
            return dt;
        }

        /// 
        /// 新增產品後使相關快取失效
        /// 
        public void InvalidateProductsCache()
        {
            // 簡單做法:移除所有前綴快取 (實務建議精確鍵值)
            foreach (DictionaryEntry entry in HttpRuntime.Cache)
            {
                if (entry.Key.ToString().StartsWith(CacheKeyPrefix))
                    HttpRuntime.Cache.Remove(entry.Key.ToString());
            }
        }
    }
}

表現層使用方式:ObjectDataSource 整合 CL

<asp:ObjectDataSource ID="odsProducts" runat="server" 
    TypeName="CL.ProductsCL" 
    SelectMethod="GetProducts"
    OldValuesParameterFormatString="original_{0}">
</asp:ObjectDataSource>

<asp:GridView ID="gvProducts" runat="server" DataSourceID="odsProducts" />

或程式碼後置直接呼叫:

protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
    {
        var cl = new CL.ProductsCL();
        gvProducts.DataSource = cl.GetProducts();
        gvProducts.DataBind();
    }
}

快取相依性進階:SqlCacheDependency (SQL Server 2005+)

// Global.asax Application_Start 啟用輪詢
SqlCacheDependencyAdmin.EnableNotifications("NorthwindConnectionString");
SqlCacheDependencyAdmin.EnableTableForNotifications("NorthwindConnectionString", "Products");

// CL 中使用
CacheDependency sqlDep = new SqlCacheDependency("NorthwindConnectionString", "Products");
HttpRuntime.Cache.Insert(cacheKey, dt, sqlDep, 
    Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration);

資料表異動時 SQL Server 通知 ASP.NET,快取自動失效,無需輪詢間隔延遲。

快取層擴充建議

  • 介面化:定義 ICacheProvider 介面,實作 HttpRuntimeCacheProvider、RedisCacheProvider、MemoryCacheProvider,支援未來遷移分散式快取。
  • 快取鍵值規範:採用 {Entity}_{Method}_{ParametersHash} 格式,如 Products_GetByCategory_5,便於精確失效。
  • 快取統計:記錄 Hit/Miss 率、快取大小、淘汰次數,導出效能儀表板。
  • 標籤式失效:實作 CacheTag 機制,InvalidateByTag("Products") 一次清除相關所有快取。

結語

獨立快取層是分層架構成熟的標誌,將横切關注點從表現層剝離,讓 BLL 專注業務規則,CL 專注快取策略,表現層專注呈現邏輯。此模式平滑遷移至 ASP.NET Core IDistributedCache、Redis、MemoryCache 等現代基礎設施。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved