C#開發微信門戶及應用(48) - 在微信框架中整合CacheManager 緩存框架

来源:http://www.cnblogs.com/wuhuacong/archive/2017/10/09/7639950.html
-Advertisement-
Play Games

在我們的很多框架或者項目應用中,緩存在一定程度上可以提高程式的響應速度,以及減輕伺服器的承載壓力,因此在一些地方我們都考慮引入緩存模塊,這篇隨筆介紹使用開源緩存框架CacheManager來實現數據的緩存,在微信開發框架中,我們有一些常用的處理也需要應用到緩存,因此本隨筆以微信框架為例介紹緩存的實際... ...


 在我們的很多框架或者項目應用中,緩存在一定程度上可以提高程式的響應速度,以及減輕伺服器的承載壓力,因此在一些地方我們都考慮引入緩存模塊,這篇隨筆介紹使用開源緩存框架CacheManager來實現數據的緩存,在微信開發框架中,我們有一些常用的處理也需要應用到緩存,因此本隨筆以微信框架為例介紹緩存的實際使用,實際上,在我們很多框架中,如混合式開發框架、Web開發框架、Bootstrap開發框架中,這個模塊都是通用的。

1、框架的緩存設計

在我們的微信開發框架中,緩存作為資料庫和對外介面之間的一個分層,提供數據的緩存響應處理,如下結構所示是Web API層對緩存的架構設計。

在緩存的處理中,我側重於使用CacheManager,這個緩存框架是一個集大成者,關於CacheManager 的介紹,我們可以回顧下我之前的隨筆《.NET緩存框架CacheManager在混合式開發框架中的應用(1)-CacheManager的介紹和使用》。

CacheManager是一個以C#語言開發的開源.Net緩存框架抽象層。它不是具體的緩存實現,但它支持多種緩存提供者(如Redis、Memcached等)並提供很多高級特性。
CacheManager 主要的目的使開發者更容易處理各種複雜的緩存場景,使用CacheManager可以實現多層的緩存,讓進程內緩存在分散式緩存之前,且僅需幾行代碼來處理。
CacheManager 不僅僅是一個介面去統一不同緩存提供者的編程模型,它使我們在一個項目裡面改變緩存策略變得非常容易,同時也提供更多的特性:如緩存同步、併發更新、序列號、事件處理、性能計算等等,開發人員可以在需要的時候選擇這些特性。

CacheManager的GitHub源碼地址為:https://github.com/MichaCo/CacheManager,如果需要具體的Demo及說明,可以訪問其官網:http://cachemanager.michaco.net

 

2、在微信框架中整合CacheManager 緩存框架

在使用CacheManager 緩存的時候,我們可以直接使用相關對象進行處理,首先需要定義一個類來進行初始化緩存的設置,然後進行調用,調用的時候可以使用IOC的方式構建對象,如下代碼所示創建一個自定義的緩存管理類

    /// <summary>
    /// 基於CacheManager的介面處理
    /// </summary>
    public class CacheManager : ICacheManager
    {
        /// <summary>
        /// ICacheManager對象
        /// </summary>
        public ICacheManager<object> Manager { get; set; }

        /// <summary>
        /// 預設構造函數
        /// </summary>
        public CacheManager()
        {
            // 初始化緩存管理器
            Manager = CacheFactory.Build("getStartedCache", settings =>
            {
                settings
                .WithSystemRuntimeCacheHandle("handleName")
                .And
                .WithRedisConfiguration("redis", config =>
                {
                    config.WithAllowAdmin()
                        .WithDatabase(0)
                        .WithEndpoint("localhost", 6379);
                })
                .WithMaxRetries(100)
                .WithRetryTimeout(50)
                .WithRedisBackplane("redis")
                .WithRedisCacheHandle("redis", true)
                ;
            });
        }
    }
}

然後在Autofac的配置文件中配置緩存的相關信息,如下文件所示。

如果直接使用Autofac的構造類來處理,那麼調用緩存處理的代碼如下所示。

            //通過AutoFac工廠獲取對應的介面實現
            var cache = AutoFactory.Instatnce.Container.Resolve<ICacheManager>();
            if (cache != null)
            {
                accountInfo = cache.Manager.Get(key) as AccountInfo;
                if (accountInfo == null)
                {
                    var value = BLLFactory<Account>.Instance.FindByID(accountId);
                    var item = new CacheItem<object>(key, value, ExpirationMode.Absolute, TimeSpan.FromMinutes(TimeOut_Minutes));
                    cache.Manager.Put(item);

                    accountInfo = cache.Manager.Get(key) as AccountInfo;
                }
            } 

 

如果為了使用方便,我們還可以對這個輔助類進行進一步的封裝,以便對它進行統一的調用處理即可。

    /// <summary>
    /// 基於.NET CacheManager的緩存管理,文檔參考:http://cachemanager.michaco.net/documentation
    /// </summary>
    public class CacheManagerHelper
    {
        /// <summary>
        /// 鎖定處理變數
        /// </summary>
        private static readonly object locker = new object();
     
        /// <summary>
        /// 創建一個緩存的鍵值,並指定響應的時間範圍,如果失效,則自動獲取對應的值
        /// </summary>
        /// <typeparam name="T">對象類型</typeparam>
        /// <param name="key">對象的鍵</param>
        /// <param name="cachePopulate">獲取緩存值的操作</param>
        /// <param name="expiration">失效的時間範圍</param>
        /// <param name="mode">失效類型</param>
        /// <returns></returns>
        public static T GetCacheItem<T>(string key, Func<T> cachePopulate, TimeSpan expiration, 
            string region = "_", ExpirationMode mode = ExpirationMode.Sliding) where T :class 
        {
            CacheItem<object> outItem = null;
            //通過AutoFac工廠獲取對應的介面實現
            var cache = AutoFactory.Instatnce.Container.Resolve<ICacheManager>();
            if (cache != null)
            {
                if (cache.Manager.Get(key, region) == null)
                {
                    lock (locker)
                    {
                        if (cache.Manager.Get(key, region) == null)
                        {
                            //Add、Put差異,Add只有在空值的情況下執行加入並返回true,Put總會替換並返回True
                            //如果按下麵的方式加入,那麼會留下歷史丟棄的鍵值: cache.Manager.Put(key, value);

                            var value = cachePopulate();
                            var item = new CacheItem<object>(key, region, value, mode, expiration);
                            cache.Manager.Put(item);
                        }
                    }
                }

                return cache.Manager.Get(key, region) as T;
            }
            else
            {                
                throw new ArgumentNullException("AutoFac配置參數錯誤,請檢查autofac.config是否存在ICacheManager的定義");
            }
        }
    }

不過由於官方已經提供了一個類似上面的代碼邏輯的TryGetOrAdd方法,這個方法的定義如下所示。

TryGetOrAdd(String, String, Func<String, String, TCacheValue>, out TCacheValue)

Tries to either retrieve an existing item or add the item to the cache if it does not exist. The valueFactory will be evaluated only if the item does not exist.

 
Declaration
bool TryGetOrAdd(string key, string region, Func<string, string, TCacheValue> valueFactory, out TCacheValue value)
Parameters
TypeNameDescription
String key

The cache key.

String region

The cache region.

Func<StringString, TCacheValue> valueFactory

The method which creates the value which should be added.

TCacheValue value

The cache value.

Returns
TypeDescription
Boolean

True if the operation succeeds, False in case there are too many retries or the valueFactory returns null.

我們根據這個參數的定義,可以進一步簡化上面的輔助類代碼。

                cache.Manager.TryGetOrAdd(key, region, (_key, _region) =>{ 
                    var value = cachePopulate();
                    var item = new CacheItem<object>(key, region, value, mode, expiration);
                    return item;
                }, out outItem);
                return outItem as T;

整個類的代碼如下所示

    /// <summary>
    /// 基於.NET CacheManager的緩存管理,文檔參考:http://cachemanager.michaco.net/documentation
    /// </summary>
    public class CacheManagerHelper
    {     
        /// <summary>
        /// 創建一個緩存的鍵值,並指定響應的時間範圍,如果失效,則自動獲取對應的值
        /// </summary>
        /// <typeparam name="T">對象類型</typeparam>
        /// <param name="key">對象的鍵</param>
        /// <param name="cachePopulate">獲取緩存值的操作</param>
        /// <param name="expiration">失效的時間範圍</param>
        /// <param name="mode">失效類型</param>
        /// <returns></returns>
        public static T GetCacheItem<T>(string key, Func<T> cachePopulate, TimeSpan expiration, 
            string region = "_", ExpirationMode mode = ExpirationMode.Sliding) where T :class 
        {
            CacheItem<object> outItem = null;
            //通過AutoFac工廠獲取對應的介面實現
            var cache = AutoFactory.Instatnce.Container.Resolve<ICacheManager>();
            if (cache != null)
            {
                cache.Manager.TryGetOrAdd(key, region, (_key, _region) =>{ 
                    var value = cachePopulate();
                    var item = new CacheItem<object>(key, region, value, mode, expiration);
                    return item;
                }, out outItem);
                return outItem as T;
            }
            else
            {                
                throw new ArgumentNullException("AutoFac配置參數錯誤,請檢查autofac.config是否存在ICacheManager的定義");
            }
        }
    }

這樣代碼就簡化了不少,而且不用自己控制讀取的線程鎖了,下麵代碼是使用輔助類實現緩存的添加及獲取處理。

        /// <summary>
        /// 為避免頻繁的對資料庫檢索,提高獲取賬號信息的速度
        /// 我們把賬號信息根據ID緩存起來,方便快速使用,提高效率。
        /// </summary>
        public static AccountInfo GetAccountByID(string accountId)
        {
            AccountInfo accountInfo = null;

            #region 使用.NET CacheManager緩存
            //正常情況下access_token有效期為7200秒,這裡使用緩存設置短於這個時間即可
            var key = "GetAccountByID_" + accountId;
            accountInfo = CacheManagerHelper.GetCacheItem<AccountInfo>(key, () =>
            {
                return BLLFactory<Account>.Instance.FindByID(accountId);
            }, TimeSpan.FromMinutes(TimeOut_Minutes));

            return accountInfo;
        }

通過這樣的輔助類封裝,我們可以在需要緩存的函數裡面,統一使用輔助類對數據進行緩存或者讀取緩存的操作。

我們也可以直接使用Autofac構建的緩存管理進行操作,如在小程式裡面,我們對用戶敏感數據的解密處理函數,如下所示。

        /// <summary>  
        /// 根據微信小程式平臺提供的解密演算法解密數據
        /// </summary>  
        [HttpGet]
        public SmallAppUserInfo Decrypt(string encryptedData, string iv, string thirdkey)
        {
            SmallAppUserInfo userInfo = null;

            //通過AutoFac工廠獲取對應的介面實現
            var cache = AutoFactory.Instatnce.Container.Resolve<ICacheManager>();
            if (cache != null)
            {
                //從緩存裡面,獲取對應的SessionKey
                var sessionkey = cache.Manager.Get(thirdkey);
                if (sessionkey != null)
                {
                    //對用戶身份加密數據進行解析,獲取包含openid等屬性的完整對象
                    IBasicApi api = new BasicApi();
                    userInfo = api.Decrypt(encryptedData, iv, sessionkey.ToString());
                }
            }
            return userInfo;
        }

 


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

-Advertisement-
Play Games
更多相關文章
  • 局部函數是C 7中的一個新功能,允許在一個函數中定義另一個函數。 何時使用局部函數? 局部函數的主要功能與匿名方法非常相似:在某些情況下,創建一個命名函數在讀者的認知負擔方面代價太大。有時,函數本身就是另一個函數的部分邏輯,因此用一個單獨的命名實體來污染“外部”範圍是毫無意義的。 您可能認為此功能是 ...
  • 在數值字元串的格式化中有很多格式化的格式,比如:用"C"表示貨幣格式,用"P"表示百分比格式,FCL中支持多種格式化字元串的方式。有時候我們會把一個數值轉換成string類型,然後再從string類型轉換成數值類型,這時候就要考慮轉換回來後的數值會不會和原來的相等呢? 首先的一種情況: 使用G常規格 ...
  • 基於ffmpeg和虹軟人臉識別庫的C#開源實現,對虹軟人臉識別庫進行了包裝,便於在C#中快速、安全的調用識別函數。同時,開源代碼中,包含完整的實現示例。 ...
  • 本篇作為技術分享系列的第四篇,詳細講一下手繪視頻中 Surface Pen 和 Surface Dial 的使用場景。 先放一張微軟官方商城的圖,Surface 的使用中結合了 Surface Pen 和 Surface Dial。 Surface Pen 的使用場景不難想象,就像 iPad 和 A ...
  • DataRead 和DataSet區別 dataset表示一個數據集,是數據在記憶體中的緩存。 可以包括多個表DatSet 連接資料庫時是非面向連接的。把表全部讀到Sql中的緩衝池,並斷開於資料庫的連接 datareader 連接資料庫時是面向連接的。讀表時,只能向前讀取,讀完數據後有用戶決定是否斷開 ...
  • C# 的集合類型中, 都有Synchronized靜態方法, 和SyncRoot實例方法 對於ArrayList以及Hashtable 集合類來講,當需要做到線程安全的時候,最好利用其自帶的屬性SyncRoot 來做到,儘管也可以使用其Synchronized()方法來實現,但是使用屬性會更好。 線 ...
  • XAML代碼: <local:WorkSpaceContent x:Class="SunCreate.CombatPlatform.Client.NoticeMarquee" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentati ...
  • 1. 引言 對於ASP.NET Core應用程式來說,我們要記住非常重要的一點是:其本質上是一個獨立的控制台應用,它並不是必需在IIS內部托管且並不需要IIS來啟動運行(而這正是ASP.NET Core跨平臺的基石)。ASP.NET Core應用程式擁有一個內置的 Self Hosted(自托管) ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...