C# MemoryCache學習筆記

来源:https://www.cnblogs.com/atomy/archive/2020/02/27/12372678.html
-Advertisement-
Play Games

很多情況下需要用到緩存,合理利用緩存一方面可以提高程式的響應速度,同時可以減少對特定資源訪問的壓力。為了避免每次請求都去訪問後臺的 資源(例如資料庫),一般會考慮將一些更新不是很頻繁的、可以重用的數據,通過一定的方式臨時地保存起來,後續的請求根據情況可以直接訪問這 些保存起來的數據,這種機制就是所謂 ...


    很多情況下需要用到緩存,合理利用緩存一方面可以提高程式的響應速度,同時可以減少對特定資源訪問的壓力。為了避免每次請求都去訪問後臺的

資源(例如資料庫),一般會考慮將一些更新不是很頻繁的、可以重用的數據,通過一定的方式臨時地保存起來,後續的請求根據情況可以直接訪問這

些保存起來的數據,這種機制就是所謂的緩存機制。

    .NET 4.0的緩存功能主要由三部分組成:System.Runtime.Caching,System.Web.Caching.Cache和Output Cache。

    MemoryCache:這個是在.NET 4.0中新增的緩存框架,Namespace:System.Runtime.Caching ,Assembly:System.Runtime.Caching.dll。

    System.Web.Caching.Cache:這個是在.NET 2.0開始就一直存在的緩存對象,一般主要用在Web中,當然也可以用於Winform裡面,不過要引用

System.Web.dll。

    Output Cache:這個是在Asp.NET裡面使用的。在ASP.NET 4.0之前,都是直接使用System.Web.Caching.Cache來緩存HTML片段。在ASP.NET 4.0

中對它進行了重新設計,提供了一個OutputCacheProvider供開發人員進行擴展,但是它預設情況下,仍然使用System.Web.Caching.Cache來做做緩存。

    下麵演示MemoryCache的簡單使用:

    1、添加一個類,命名為ConfigHelper,代碼如下:

    /// <summary>
    /// 配置幫助類
    /// </summary>
    class ConfigHelper
    {
        /// <summary>
        /// 獲取管理配置文件對象
        /// </summary>
        /// <param name="configPath">指定要管理的配置文件路徑,如果為空或不存在,則為管理程式集預設的配置文件路徑。</param>
        /// <returns></returns>
        private static Configuration GetConfiguration(string configPath = null)
        {
            if (!string.IsNullOrEmpty(configPath) && File.Exists(configPath))
            {
                ExeConfigurationFileMap map = new ExeConfigurationFileMap
                {
                    ExeConfigFilename = configPath
                };
                return ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
            }
            else
            {
                return ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
            }
        }

        /// <summary>
        /// 獲取指定配置文件+配置名稱的配置項的值
        /// </summary>
        public static string GetAppSettingValue(string key, string defaultValue = null, string configPath = null)
        {
            var config = GetConfiguration(configPath);
            var appSetting = config.AppSettings.Settings[key];
            return appSetting.Value;
        }

        /// <summary>
        /// 獲取所有配置值
        /// </summary>
        public static Dictionary<string, string> GetAppSettingValues(string configPath = null)
        {
            Dictionary<string, string> settingDic = new Dictionary<string, string>();
            var config = GetConfiguration(configPath);
            var settings = config.AppSettings.Settings;
            foreach (string key in settings.AllKeys)
            {
                settingDic[key] = settings[key].ToString();
            }
            return settingDic;
        }

        /// <summary>
        /// 設置配置值(存在則更新,不存在則新增。)
        /// </summary>
        public static void SetAppSettingValue(string key, string value, string configPath = null)
        {
            var config = GetConfiguration(configPath);
            var setting = config.AppSettings.Settings[key];
            if (setting == null)
            {
                config.AppSettings.Settings.Add(key, value);
            }
            else
            {
                setting.Value = value;
            }

            config.Save(ConfigurationSaveMode.Modified);
            ConfigurationManager.RefreshSection("appSettings");
        }

        /// <summary>
        /// 設置多個配置值(存在則更新,不存在則新增)
        /// </summary>
        public static void SetAppSettingValues(IEnumerable<KeyValuePair<string, string>> settingValues, string configPath = null)
        {
            var config = GetConfiguration(configPath);
            foreach (var item in settingValues)
            {
                var setting = config.AppSettings.Settings[item.Key];
                if (setting == null)
                {
                    config.AppSettings.Settings.Add(item.Key, item.Value);
                }
                else
                {
                    setting.Value = item.Value;
                }
            }
            config.Save(ConfigurationSaveMode.Modified);
            ConfigurationManager.RefreshSection("appSettings");
        }

        /// <summary>
        /// 刪除配置值
        /// </summary>
        public static void RemoveAppSetting(string key, string configPath = null)
        {
            var config = GetConfiguration(configPath);
            config.AppSettings.Settings.Remove(key);
            config.Save(ConfigurationSaveMode.Modified);
            ConfigurationManager.RefreshSection("appSettings");
        }

        /// <summary>
        /// 刪除多個配置值
        /// </summary>
        public static void RemoveAppSettings(string configPath = null, params string[] keys)
        {
            var config = GetConfiguration(configPath);
            if (keys != null)
            {
                foreach (string key in keys)
                {
                    config.AppSettings.Settings.Remove(key);
                }
            }
            else
            {
                config.AppSettings.Settings.Clear();
            }
            config.Save(ConfigurationSaveMode.Modified);
            ConfigurationManager.RefreshSection("appSettings");
        }

        /// <summary>
        /// 獲取連接字元串
        /// </summary>
        public static string GetConnectionString(string name, string defaultconnString = null, string configPath = null)
        {
            var config = GetConfiguration(configPath);
            var connStringSettings = config.ConnectionStrings.ConnectionStrings[name];
            if (connStringSettings == null)
            {
                return defaultconnString;
            }
            return connStringSettings.ConnectionString;
        }

        /// <summary>
        /// 獲取指定配置文件+連接名稱的連接字元串配置項
        /// </summary>
        public static ConnectionStringSettings GetConnectionStringSetting(string name, string configPath = null)
        {
            var config = GetConfiguration(configPath);
            var connStringSettings = config.ConnectionStrings.ConnectionStrings[name];
            return connStringSettings;
        }

        /// <summary>
        /// 獲取所有的連接字元串配置項
        /// </summary>
        public static Dictionary<string, ConnectionStringSettings> GetConnectionStringSettings(string configPath = null)
        {
            var config = GetConfiguration(configPath);
            var connStringSettingDic = new Dictionary<string, ConnectionStringSettings>();
            var connStringSettings = ConfigurationManager.ConnectionStrings;
            foreach (ConnectionStringSettings item in connStringSettings)
            {
                connStringSettingDic[item.Name] = item;
            }
            return connStringSettingDic;
        }

        /// <summary>
        /// 設置連接字元串的值(存在則更新,不存在則新增。)
        /// </summary>
        public static void SetConnectionString(string name, string connString, string provider, string configPath = null)
        {
            var config = GetConfiguration(configPath);
            ConnectionStringSettings connStringSettings = config.ConnectionStrings.ConnectionStrings[name];
            if (connStringSettings != null)
            {
                connStringSettings.ConnectionString = connString;
                connStringSettings.ProviderName = provider;
            }
            else
            {
                connStringSettings = new ConnectionStringSettings(name, connString, provider);
                config.ConnectionStrings.ConnectionStrings.Add(connStringSettings);
            }

            config.Save(ConfigurationSaveMode.Modified);
            ConfigurationManager.RefreshSection("connectionStrings");
        }

        /// <summary>
        /// 設置多個連接字元串的值(存在則更新,不存在則新增。)
        /// </summary>
        public static void SetConnectionStrings(IEnumerable<ConnectionStringSettings> connStringSettings, string configPath = null)
        {
            var config = GetConfiguration(configPath);
            foreach (var item in connStringSettings)
            {
                ConnectionStringSettings connStringSetting = config.ConnectionStrings.ConnectionStrings[item.Name];
                if (connStringSetting != null)
                {
                    connStringSetting.ConnectionString = item.ConnectionString;
                    connStringSetting.ProviderName = item.ProviderName;
                }
                else
                {
                    config.ConnectionStrings.ConnectionStrings.Add(item);
                }
            }

            config.Save(ConfigurationSaveMode.Modified);
            ConfigurationManager.RefreshSection("connectionStrings");
        }

        /// <summary>
        /// 刪除連接字元串配置項
        /// </summary>
        public static void RemoveConnectionString(string name, string configPath = null)
        {
            var config = GetConfiguration(configPath);
            config.ConnectionStrings.ConnectionStrings.Remove(name);
            config.Save(ConfigurationSaveMode.Modified);
            ConfigurationManager.RefreshSection("connectionStrings");
        }

        /// <summary>
        /// 刪除多個連接字元串配置項
        /// </summary>
        public static void RemoveConnectionStrings(string configPath = null, params string[] names)
        {
            var config = GetConfiguration(configPath);
            if (names != null)
            {
                foreach (string name in names)
                {
                    config.ConnectionStrings.ConnectionStrings.Remove(name);
                }
            }
            else
            {
                config.ConnectionStrings.ConnectionStrings.Clear();
            }
            config.Save(ConfigurationSaveMode.Modified);
            ConfigurationManager.RefreshSection("connectionStrings");
        }
    }
View Code

    2、添加一個類,命名為MemoryCacheHelper(註意需引用System.Runtime.Caching.dll),代碼如下:

    /// <summary>
    /// 記憶體緩存幫助類,支持絕對過期時間、滑動過期時間、文件依賴三種緩存方式。
    /// </summary>
    class MemoryCacheHelper
    {
        private static readonly object _locker1 = new object(), _locker2 = new object();

        /// <summary>
        /// 取緩存項,如果不存在則返回空。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public static T GetCacheItem<T>(string key)
        {
            try
            {
                return (T)MemoryCache.Default[key];
            }
            catch
            {
                return default(T);
            }
        }

        /// <summary>
        /// 是否包含指定鍵的緩存項
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static bool Contains(string key)
        {
            return MemoryCache.Default.Contains(key);
        }

        /// <summary>
        /// 取緩存項,如果不存在則新增緩存項。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="cachePopulate"></param>
        /// <param name="slidingExpiration"></param>
        /// <param name="absoluteExpiration"></param>
        /// <returns></returns>
        public static T GetOrAddCacheItem<T>(string key, Func<T> cachePopulate, TimeSpan? slidingExpiration = null, DateTime? absoluteExpiration = null)
        {
            if (string.IsNullOrWhiteSpace(key)) throw new ArgumentException("Invalid cache key");
            if (cachePopulate == null) throw new ArgumentNullException("cachePopulate");
            if (slidingExpiration == null && absoluteExpiration == null) throw new ArgumentException("Either a sliding expiration or absolute must be provided");

            if (MemoryCache.Default[key] == null)
            {
                lock (_locker1)
                {
                    if (MemoryCache.Default[key] == null)
                    {
                        T cacheValue = cachePopulate();
                        if (!typeof(T).IsValueType && cacheValue == null)   //如果是引用類型且為NULL則不存緩存
                        {
                            return cacheValue;
                        }

                        var item = new CacheItem(key, cacheValue);
                        var policy = CreatePolicy(slidingExpiration, absoluteExpiration);

                        MemoryCache.Default.Add(item, policy);
                    }
                }
            }

            return (T)MemoryCache.Default[key];
        }

        /// <summary>
        /// 取緩存項,如果不存在則新增緩存項。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="cachePopulate"></param>
        /// <param name="dependencyFilePath"></param>
        /// <returns></returns>
        public static T GetOrAddCacheItem<T>(string key, Func<T> cachePopulate, string dependencyFilePath)
        {
            if (string.IsNullOrWhiteSpace(key)) throw new ArgumentException("Invalid cache key");
            if (cachePopulate == null) throw new ArgumentNullException("cachePopulate");

            if (MemoryCache.Default[key] == null)
            {
                lock (_locker2)
                {
                    if (MemoryCache.Default[key] == null)
                    {
                        T cacheValue = cachePopulate();
                        if (!typeof(T).IsValueType && cacheValue == null)   //如果是引用類型且為NULL則不存緩存
                        {
                            return cacheValue;
                        }

                        var item = new CacheItem(key, cacheValue);
                        var policy = CreatePolicy(dependencyFilePath);

                        MemoryCache.Default.Add(item, policy);
                    }
                }
            }

            return (T)MemoryCache.Default[key];
        }

        /// <summary>
        /// 指定緩存項的一組逐出和過期詳細信息
        /// </summary>
        /// <param name="slidingExpiration"></param>
        /// <param name="absoluteExpiration"></param>
        /// <returns></returns>
        private static CacheItemPolicy CreatePolicy(TimeSpan? slidingExpiration, DateTime? absoluteExpiration)
        {
            var policy = new CacheItemPolicy();

            if (absoluteExpiration.HasValue)
            {
                policy.AbsoluteExpiration = absoluteExpiration.Value;
            }
            else if (slidingExpiration.HasValue)
            {
                policy.SlidingExpiration = slidingExpiration.Value;
            }

            policy.Priority = CacheItemPriority.Default;

            return policy;
        }

        /// <summary>
        /// 指定緩存項的一組逐出和過期詳細信息
        /// </summary>
        /// <param name="filePath"></param>
        /// <returns></returns>
        private static CacheItemPolicy CreatePolicy(string filePath)
        {
            CacheItemPolicy policy = new CacheItemPolicy();
            policy.ChangeMonitors.Add(new HostFileChangeMonitor(new List<string>() { filePath }));
            policy.Priority = CacheItemPriority.Default;
            return policy;
        }

        /// <summary>
        /// 移除指定鍵的緩存項
        /// </summary>
        /// <param name="key"></param>
        public static void RemoveCacheItem(string key)
        {
            if (Contains(key))
            {
                MemoryCache.Default.Remove(key);
            }
        }
    }
View Code

    3、添加一個WinForm窗體,命名為Main,並添加一個按鈕。

    4、配置App.config:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <startup> 
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
  </startup>
  <connectionStrings>
    <add name ="connString" connectionString="server=.;database=db_test;uid=sa;pwd=********;" />
  </connectionStrings>
</configuration>

    5、Main窗體代碼如下:

        private void button1_Click(object sender, EventArgs e)
        {
            int times1 = 0, times2 = 0;
            for (int i = 0; i < 10; i++)
            {
                if (MemoryCacheHelper.Contains("connString"))
                {
                    times1++;
                }
                else
                {
                    times2++;
                    string connstr = MemoryCacheHelper.GetOrAddCacheItem("connString", () =>
                    {
                        return ConfigHelper.GetConnectionString("connString", null);
                    }, Application.StartupPath + @"\App.config");
                }
            }
            MessageBox.Show($"記憶體緩存讀取次數:{times1},非記憶體緩存讀取次數:{times2}", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

    6、運行結果如下:

    參考自:

    https://www.cnblogs.com/mq0036/p/10312945.html

    https://www.cnblogs.com/zuowj/p/8366735.html

    https://www.cnblogs.com/zuowj/p/8440902.html


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • springBoot1.x升級到springBoot2.x,出現預設的mysql驅動包版本的問題,需要修改jdbc驅動類和連接字元串 ...
  • 直接使用 CIL - .NET 上的彙編語言編寫 .NET Standard 類庫 ...
  • 目 錄 1. 概述... 1 2. iNeuDaemon部署... 2 3. iNeuDaemon配置監控服務項... 3 4. 應用效果... 3 1. 概述 iNeuDaemon是Windows平臺後臺守護進程,用於監測服務進程,如果出現異常退出、遠程運維重新啟動等場景,那麼可以部署iNeuDa ...
  • 實現方式:WinForm自定義控制項,繼承系統Label控制項實現。 第1步:創建“組件”,取名為:MarkLabel 第2步:修改添加如下代碼: /* 添加命名空間引用: * using System.Windows.Forms; * using System.Drawing; * */ public ...
  • 1,博圖數據塊的數據排列原則: 數據對齊演算法: 將當前地址對齊到整數:numBytes = (int)Math.Ceiling(numBytes); 將當前地址對齊到偶整數: numBytes = Math.Ceiling(numBytes); if ((numBytes / 2 - Math.Fl... ...
  • ABP框架 .NetCore3.x版本 1.首先找到xxx.Core 項目,添加引用Microsoft.EntityFrameworkCore.Tools 2.找到xxx.EntityFrameworkCore項目,將原有sqlserver的引用改為mysql引用 3. 找到Host項目中的配置文件 ...
  • 0x01 前言 ASP.NET Core在預設發佈情況下,會啟動預編譯將試圖編譯成 xx.Views.dll ,也許在視圖中打算修改一處很細小的地方我們需要再重新編譯視圖進行發佈。下麵我將從 ASP.NET Core 3 之前版本到 ASP.NET Core 3X 之後版本的一個配置列下下方供大家參 ...
  • static int hHook = 0; public delegate int HookProc(int nCode, int wParam, IntPtr lParam); //LowLevel鍵盤截獲,如果是WH_KEYBOARD=2,並不能對系統鍵盤截取,Acrobat Reader會在你 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...