出售域名 11365.com.cn
有需要请联系 16826375@qq.com
在手机上浏览
在手机上浏览

.Net CacheManager封装

创建时间:2023-02-05

一、简介

CacheManager是一款开源组件,地址是https://github.com/MichaCo/CacheManager
里面不但有详细的简介,还有很多demo,demo的地址是https://cachemanager.michaco.net/documentation
好像没有中文网页,大家将就着看吧!这里就不再赘述了。

二、封装

1)引用
通过Nuget引用三个组件:CacheManager.Core、CacheManager.SystemRuntimeCaching、CacheManager.StackExchange.Redis
CacheManager.Core是核心类,一定要引用.。
CacheManager.SystemRuntimeCaching是.net自带缓存的实现,使用高速缓存;
CacheManager.StackExchange.Redis是redis缓存的实现,适用于分布式缓存。


当然,并不是说我们引用了就必须使用,在实际项目中可能没有用到Redis,那么我们配置中不使用即可。

2)操作
把缓存操作封装成一个静态类:CacheUtils。
由于CacheManager并没有提供关于所有Key的读取方法或者属性,我们就定义了一个属性CacheKeys,在事件中维护这些缓存键。
缓存操作提供了增加/移除方法,如果缓存键已存在,增加将覆盖原数据。

using System;
using System.Collections.Generic;
using System.Linq;
using CacheManager.Core;

namespace CacheManagerDemo
{
    /// <summary>
    /// 缓存工具类,整合了cachemanager <br/>
    /// 开源地址:https://github.com/MichaCo/CacheManager"
    /// </summary>
    public static class CacheUtils
    {
        private static readonly ICacheManager<object> cache;

        /// <summary>
        /// 缓存键集合,region "_" key,如果没有指定region,那么就用global
        /// </summary>
        public static List<string> CacheKeys { get; set; }

        /// <summary>
        /// 初始化
        /// </summary>
        static CacheUtils()
        {
            if (CacheKeys == null) CacheKeys = new List<string>(); //初始化

            cache = CacheFactory.Build("ctt_web_caches", settings =>
            {
                if (CacheConfig.CacheType == CacheType.RedisCache.ToString())
                {
                    settings
                    .WithSystemRuntimeCacheHandle("frontCache") //前端使用服务器缓存
                    .And
                    .WithRedisConfiguration("redisBackCache", config => //Redis缓存配置
                    {
                        config.WithAllowAdmin()
                        .WithDatabase(0)
                        .WithEndpoint(CacheConfig.RedisServer, CacheConfig.RedisPort) //redis服务
                        .WithPassword(CacheConfig.RedisPwd) //密码
                        .EnableKeyspaceEvents();
                    })
                    .WithMaxRetries(1000)//尝试次数
                    .WithRetryTimeout(100)//尝试超时时间
                    .WithRedisBackplane("redisBackCache") //Redis做为后台缓存,内存缓存做为前台缓存,Redis缓存会和内存缓存同步
                    .WithRedisCacheHandle("redisBackCache", true);//redis缓存handle
                }
                else
                {
                    settings.WithSystemRuntimeCacheHandle("frontCache");
                }
            });

            #region 缓存事件

            /*以下操作会影响到key集合*/

            cache.OnAdd  = (s, arg) =>
            {
                string key = string.IsNullOrEmpty(arg.Region) ? "global_"   arg.Key : arg.Region   "_"   arg.Key;
                if (!CacheKeys.Contains(key))
                    CacheKeys.Add(key);
            };
            cache.OnPut  = (s, arg) =>
            {
                string key = string.IsNullOrEmpty(arg.Region) ? "global_"   arg.Key : arg.Region   "_"   arg.Key;
                if (!CacheKeys.Contains(key))
                    CacheKeys.Add(key);
            };
            cache.OnRemove  = (s, arg) => { CacheKeys.Remove((string.IsNullOrEmpty(arg.Region) ? "global" : arg.Region)   "_"   arg.Key); };

            cache.OnClearRegion  = (s, arg) => { CacheKeys.RemoveAll(x => x.StartsWith(arg.Region   "_")); };
            cache.OnClear  = (s, arg) => { CacheKeys.RemoveAll(x => true); };

            cache.OnRemoveByHandle  = (s, arg) => { CacheKeys.Remove((string.IsNullOrEmpty(arg.Region) ? "global" : arg.Region)   "_"   arg.Key); };

            #endregion
        }

        #region 缓存操作

        /// <summary>
        /// 是否存在缓存
        /// </summary>
        /// <param name="key"></param>
        /// <param name="region"></param>
        /// <returns></returns>
        public static bool Exists(string key, string region = null)
        {
            return !string.IsNullOrEmpty(region)
                ? cache.Exists(key, region)
                : cache.Exists(key);
        }

        /// <summary>
        /// 添加缓存
        /// </summary>
        /// <param name="key">键</param>
        /// <param name="obj">值对象</param>
        /// <param name="expires">超地时间(秒),默认24小时</param>
        /// <param name="region">域</param>
        public static void Insert(string key, object obj, int expires = 3600 * 24, string region = null)
        {
            var item = !string.IsNullOrEmpty(region)
                ? new CacheItem<object>(key, region, obj, ExpirationMode.Sliding, TimeSpan.FromSeconds(expires))
                : new CacheItem<object>(key, obj, ExpirationMode.Sliding, TimeSpan.FromSeconds(expires));

            cache.Put(item);
        }

        /// <summary>
        /// 读缓存
        /// </summary>
        /// <param name="key"></param>
        /// <param name="region"></param>
        /// <returns></returns>
        public static object Get(string key, string region = null)
        {
            return !string.IsNullOrEmpty(region)
                ? cache.Get(key, region)
                : cache.Get(key);
        }

        /// <summary>
        /// 读缓存
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="region"></param>
        /// <returns></returns>
        public static T Get<T>(string key, string region = null)
        {
            var obj = Get(key, region);
            return obj != null
                ? (T)obj
                : default(T);
        }

        /// <summary>
        /// 查找域的所有键
        /// </summary>
        /// <param name="region"></param>
        /// <returns></returns>
        public static IEnumerable<string> GetKeys(string region)
        {
            if (CacheKeys == null) return null;
            return CacheKeys.Where(p => p.StartsWith(region   "_")).ToList();
        }

        /// <summary>
        /// 删除缓存
        /// </summary>
        /// <param name="key"></param>
        /// <param name="region"></param>
        public static void Remove(string key, string region = null)
        {
            if (!string.IsNullOrEmpty(region))
                cache.Remove(key, region);
            else
                cache.Remove(key); //即使没有这个key也不会报错
        }

        /// <summary>
        /// 清除缓存
        /// </summary>
        /// <param name="region"></param>
        public static void Clear(string region = null)
        {
            if (!string.IsNullOrEmpty(region))
                cache.ClearRegion(region);
            else
                cache.Clear();
        }

        #endregion        
    }
}

三、测试

1)redis配置

如果还没有安装Redis服务,可以在https://github.com/tporadowski/redis/releases下载并安装成服务。
然后在App.config或者Web.config的AppSetting中进行配置

<appSettings>
	<!--缓存类型:LocalCache / RedisCache,如果配置成RedisCache,需要安装Redis服务-->
	<add key="CacheType" value="LocalCache"/>
	<!--Redis服务址址-->
	<add key="RedisServer" value="localhost"/>
	<!--Redis服务端口-->
	<add key="RedisPort" value="6379"/>
	<!--Redis服务密码-->
	<add key="RedisPwd" value="jasonlee"/>
	<!--Redis服务使用的数据库序号-->
	<add key="DBNum" value="0"/>
</appSettings>

这些配置在上面的工具类中使用,还需要一个读配置的类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CacheManagerDemo
{
    public enum CacheType
    {
        LocalCache,
        RedisCache
    }

    public static class CacheConfig
    {
        public static string CacheType { get; set; }
        public static string RedisServer { get; set; }
        public static int RedisPort { get; set; } = 6379;
        public static string RedisPwd { get; set; }
        public static int DBNum { get; set; } = 0;

        static CacheConfig()
        {
            ReadConfig(); //初始化
        }

        public static void ReadConfig()
        {
            CacheType = System.Configuration.ConfigurationManager.AppSettings["CacheType"];
            RedisServer = System.Configuration.ConfigurationManager.AppSettings["RedisServer"];

            var intRedisPort = 6379;
            var strRedisPort = System.Configuration.ConfigurationManager.AppSettings["RedisPort"];
            if (int.TryParse(strRedisPort, out intRedisPort))
                RedisPort = intRedisPort;

            RedisPwd = System.Configuration.ConfigurationManager.AppSettings["RedisPwd"];

            var intDBNum = 0;
            var strDBNum = System.Configuration.ConfigurationManager.AppSettings["DBNum"];
            if (int.TryParse(strRedisPort, out intDBNum))
                DBNum = intDBNum;
        }
    }
}


2)测试类

最后我们造一个测试数据,验证是否正确

using System;

namespace CacheManagerDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            //添加普通缓存
            CacheUtils.Insert("key1", "123");
            //添加对象缓存
            CacheUtils.Insert("key2", new Student() { Name = "jasonlee", Age = 18 });
            //添加到域
            CacheUtils.Insert("key3", "456", 3600 * 24, "region1");
            CacheUtils.Insert("key3.1", "789", 3600 * 24, "region1");
            //添加很短时间的缓存
            CacheUtils.Insert("key4", "shorttime", 1); //1秒过后就超时,系统会自动删除这个key

            //读取缓存
            Console.WriteLine("共有缓存键:{0}", CacheUtils.CacheKeys.Count);

            Console.WriteLine("-----------------------");
            foreach (var key in CacheUtils.CacheKeys)
            {
                Console.WriteLine("缓存键:{0}", key);
            }
            Console.WriteLine("-----------------------");

            Console.WriteLine("key1:{0}", CacheUtils.Get("key1").ToString());
            Console.WriteLine("key2:{0}", CacheUtils.Get<Student>("key2").Name);
            Console.WriteLine("key3:{0}", CacheUtils.Get("key3", "region1").ToString());
            //模拟延迟5秒
            Console.WriteLine("key4:{0}", CacheUtils.Get("key4").ToString());
            System.Threading.Thread.Sleep(5000);
            Console.WriteLine("已经过去了5秒...");
            Console.WriteLine("key4:{0}", CacheUtils.Get("key4") == null ? "不存在" : CacheUtils.Get("key4").ToString());
            Console.WriteLine("共有缓存键:{0}", CacheUtils.CacheKeys.Count);

            //清除缓存key1
            CacheUtils.Remove("key1");
            Console.WriteLine("是否存在key1:{0}", CacheUtils.Exists("key1") ? "存在" : "不存在");
            
            //清除域的缓存
            CacheUtils.Clear("region1");
            Console.WriteLine("清除域region1后共有缓存键:{0}", CacheUtils.CacheKeys.Count);

            Console.WriteLine("-----------------------");
            foreach (var key in CacheUtils.CacheKeys)
            {
                Console.WriteLine("缓存键:{0}", key);
            }
            Console.WriteLine("-----------------------");

            //清除所有缓存
            CacheUtils.Clear();
            Console.WriteLine("清空缓存后数量:{0}", CacheUtils.CacheKeys.Count);
            
            Console.WriteLine("We are done...");
            Console.ReadKey();
        }
    }

    [Serializable]
    public class Student
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }
}

 

最后,我们打开Redis客户端,查看是否写入了数据


模板下载地址