ASP.NET MVC 使用靜態型別快取資料,減少重複讀取資料庫

2025-01-16

筆記如何設計使用靜態型別來快取資料,減少重複讀取資料庫的情況,並且透過 ASP.NET MVC 5 來實作。

logo

說明

本次實作將 System Settings Value 資料表進行靜態型別的快取實作。

首先設計 Service Class,因為 Setttings 是 Key-Value 的形式,所以使用 Dictionary 來儲存。

關鍵是搭配 InitializeAsync 方法,透過 Entity Framework 來讀取資料庫的資料,並且轉換成 Dictionary。

這個方法會在 Application 啟動時執行一次,之後就是沿用記憶體的快取資料,除非有資料異動。

public static class SettingService
{
    public static Dictionary<string, string> Settings { get; set; }

    /// <summary>
    /// Get setting value by key.
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    /// <exception cref="KeyNotFoundException"></exception>
    public static string Get(string key)
    {
        if (Settings.ContainsKey(key))
        {
            return Settings[key];
        }
        else
        {
            return $"Setting key '{key}' not found.";
        }
    }

    public static async Task InitializeAsync()
    {
        using (var db = new WebAppEntities())
        {
            Settings = await db.Settings.ToDictionaryAsync(s => s.SettingKey, s => s.Value);
        }
    }
}

接著在 Global.asax.cs 中的 Application_Start 方法中呼叫 InitializeAsync 方法。

透過 Task.Run 就可以在同步方法中呼叫非同步方法 😎

try
{
    Task.Run(() => SettingService.InitializeAsync()).Wait();
}
catch (Exception)
{
    Debug.WriteLine("Failed to initialize SettingService");
}

接著考量到資料異動的情況,在 Settings 的 Controller 中新增 Private Method 來重新讀取資料。

private void UpdateSettingsInStaticClass()
{
    try
    {
        Task.Run(() => SettingService.InitializeAsync()).Wait();
    }
    catch (Exception)
    {
        Debug.WriteLine("Failed to update SettingService");
    }
}

之後在 CREATE, EDIT, DELETE 的 POST Action 中呼叫這個方法。

[HttpPost]
public ActionResult Create(Settings settings)
{
    if (ModelState.IsValid)
    {
        ...
        UpdateSettingsInStaticClass();

        return RedirectToAction("Index");
    }

    return View(settings);
}