4

.NET 6 基于IDistributedCache实现Redis与MemoryCache的缓存帮助类 - gmval

 1 year ago
source link: https://www.cnblogs.com/gmval/p/16953063.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

本文通过IDistributedCache的接口方法,实现RedisMemoryCache统一帮助类。只需要在配置文件中简单的配置一下,就可以实现Redis与MemoryCache的切换。

IDistributedCache

IDistributedCache 方法:

方法 说明
Get(String) 获取具有给定键的值。
GetAsync(String, CancellationToken) 获取具有给定键的值。
Refresh(String) 基于缓存中某个值的键刷新该值,并重置其可调到期超时(如果有)。
RefreshAsync(String, CancellationToken) 基于缓存中某个值的键刷新该值,并重置其可调到期超时(如果有)。
Remove(String) 删除具有给定键的值。
RemoveAsync(String, CancellationToken) 删除具有给定键的值。
Set(String, Byte[], DistributedCacheEntryOptions) 设置具有给定键的值。
SetAsync(String, Byte[], DistributedCacheEntryOptions, CancellationToken) 设置具有给定键的值。

IDistributedCache 还提供了一些扩展方法,本文的帮助类就是通过扩展方法完成的。

IDistributedCache 扩展方法:

方法 说明
GetString(IDistributedCache, String) 使用指定的键从指定的缓存中获取字符串。
GetStringAsync(IDistributedCache, String, CancellationToken) 使用指定的键从指定的缓存异步获取字符串。
Set(IDistributedCache, String, Byte[]) 使用指定的键设置指定缓存中的字节序列。
SetAsync(IDistributedCache, String, Byte[], CancellationToken) 使用指定的键异步设置指定缓存中的字节序列。
SetString(IDistributedCache, String, String) 使用指定的键在指定的缓存中设置字符串。
SetString(IDistributedCache, String, String, DistributedCacheEntryOptions) 使用指定的键在指定的缓存中设置字符串。
SetStringAsync(IDistributedCache, String, String, DistributedCacheEntryOptions, CancellationToken) 使用指定的键在指定的缓存中异步设置字符串。
SetStringAsync(IDistributedCache, String, String, CancellationToken) 使用指定的键在指定的缓存中异步设置字符串。

ICache 接口

ICache接口提供了设置缓存、获取缓存、删除缓存和刷新缓存的接口方法。



namespace CacheHelper
{
    public interface ICache
    {
        #region 设置缓存 
        /// <summary>
        /// 设置缓存
        /// </summary>
        /// <param name="key">缓存Key</param>
        /// <param name="value">值</param>
        void SetCache(string key, object value);
        /// <summary>
        /// 设置缓存
        /// </summary>
        /// <param name="key">缓存Key</param>
        /// <param name="value">值</param>
        Task SetCacheAsync(string key, object value);

        /// <summary>
        /// 设置缓存
        /// 注:默认过期类型为绝对过期
        /// </summary>
        /// <param name="key">缓存Key</param>
        /// <param name="value">值</param>
        /// <param name="timeout">过期时间间隔</param>
        void SetCache(string key, object value, TimeSpan timeout);

        /// <summary>
        /// 设置缓存
        /// 注:默认过期类型为绝对过期
        /// </summary>
        /// <param name="key">缓存Key</param>
        /// <param name="value">值</param>
        /// <param name="timeout">过期时间间隔</param>
        Task SetCacheAsync(string key, object value, TimeSpan timeout);

        /// <summary>
        /// 设置缓存
        /// 注:默认过期类型为绝对过期
        /// </summary>
        /// <param name="key">缓存Key</param>
        /// <param name="value">值</param>
        /// <param name="timeout">过期时间间隔</param>
        /// <param name="expireType">过期类型</param>  
        void SetCache(string key, object value, TimeSpan timeout, ExpireType expireType);

        /// <summary>
        /// 设置缓存
        /// 注:默认过期类型为绝对过期
        /// </summary>
        /// <param name="key">缓存Key</param>
        /// <param name="value">值</param>
        /// <param name="timeout">过期时间间隔</param>
        /// <param name="expireType">过期类型</param>  
        Task SetCacheAsync(string key, object value, TimeSpan timeout, ExpireType expireType);
        #endregion

        #region 获取缓存

        /// <summary>
        /// 获取缓存
        /// </summary>
        /// <param name="key">缓存Key</param>
        string GetCache(string key);

        /// <summary>
        /// 获取缓存
        /// </summary>
        /// <param name="key">缓存Key</param>
        Task<string> GetCacheAsync(string key);
        /// <summary>
        /// 获取缓存
        /// </summary>
        /// <param name="key">缓存Key</param>
        T GetCache<T>(string key);
        /// <summary>
        /// 获取缓存
        /// </summary>
        /// <param name="key">缓存Key</param>
        Task<T> GetCacheAsync<T>(string key);

        #endregion

        #region 删除缓存

        /// <summary>
        /// 清除缓存
        /// </summary>
        /// <param name="key">缓存Key</param>
        void RemoveCache(string key);

        /// <summary>
        /// 清除缓存
        /// </summary>
        /// <param name="key">缓存Key</param>
        Task RemoveCacheAsync(string key);

        #endregion

        #region 刷新缓存
        /// <summary>
        /// 刷新缓存
        /// </summary>
        /// <param name="key">缓存Key</param>
        void RefreshCache(string key);
        /// <summary>
        /// 刷新缓存
        /// </summary>
        /// <param name="key">缓存Key</param>
        Task RefreshCacheAsync(string key);
        #endregion
    }
}

ExpireType枚举

ExpireType枚举标识缓存的过期类型,分为绝对过期相对过期两个类型。
绝对过期:即自创建一段时间后就过期
相对过期:即该键未被访问后一段时间后过期,若此键一直被访问则过期时间自动延长。

namespace CacheHelper
{
    public enum ExpireType
    {
        /// <summary>
        /// 绝对过期
        /// 注:即自创建一段时间后就过期
        /// </summary>
        Absolute,

        /// <summary>
        /// 相对过期
        /// 注:即该键未被访问后一段时间后过期,若此键一直被访问则过期时间自动延长
        /// </summary>
        Relative,
    }
}

CacheType 枚举

是使用MemoryCache,还是RedisMemoryCache不支持分布式,Redis支持分布式。

namespace CacheHelper
{
    public enum CacheType
    {
        /// <summary>
        /// 使用内存缓存(不支持分布式)
        /// </summary>
        Memory,

        /// <summary>
        /// 使用Redis缓存(支持分布式)
        /// </summary>
        Redis
    }
}

CacheHelper 缓存帮助类

namespace CacheHelper
{
    public class CacheHelper : ICache
    {
        readonly IDistributedCache _cache;

        public CacheHelper(IDistributedCache cache)
        {
            _cache = cache;
        }

        protected string BuildKey(string idKey)
        {
            return $"Cache_{GetType().FullName}_{idKey}";
        }
        public void SetCache(string key, object value)
        {
            string cacheKey = BuildKey(key);
            _cache.SetString(cacheKey, value.ToJson());
        }

        public async Task SetCacheAsync(string key, object value)
        {
            string cacheKey = BuildKey(key);
            await _cache.SetStringAsync(cacheKey, value.ToJson());
        }

        public void SetCache(string key, object value, TimeSpan timeout)
        {
            string cacheKey = BuildKey(key);
            _cache.SetString(cacheKey, value.ToJson(), new DistributedCacheEntryOptions
            {
                AbsoluteExpiration = new DateTimeOffset(DateTime.Now + timeout)
            });
        }

        public async Task SetCacheAsync(string key, object value, TimeSpan timeout)
        {
            string cacheKey = BuildKey(key);
            await _cache.SetStringAsync(cacheKey, value.ToJson(), new DistributedCacheEntryOptions
            {
                AbsoluteExpiration = new DateTimeOffset(DateTime.Now + timeout)
            });
        }

        public void SetCache(string key, object value, TimeSpan timeout, ExpireType expireType)
        {
            string cacheKey = BuildKey(key);
            if (expireType == ExpireType.Absolute)
            {
                //这里没转换标准时间,Linux时区会有问题?
                _cache.SetString(cacheKey, value.ToJson(), new DistributedCacheEntryOptions
                {
                    AbsoluteExpiration = new DateTimeOffset(DateTime.Now + timeout)
                });
            }
            else
            {
                _cache.SetString(cacheKey, value.ToJson(), new DistributedCacheEntryOptions
                {
                    AbsoluteExpirationRelativeToNow = timeout
                });
            }
        }

        public async Task SetCacheAsync(string key, object value, TimeSpan timeout, ExpireType expireType)
        {
            string cacheKey = BuildKey(key);
            if (expireType == ExpireType.Absolute)
            {
                //这里没转换标准时间,Linux时区会有问题?
                await _cache.SetStringAsync(cacheKey, value.ToJson(), new DistributedCacheEntryOptions
                {
                    AbsoluteExpiration = new DateTimeOffset(DateTime.Now + timeout)
                });
            }
            else
            {
                await _cache.SetStringAsync(cacheKey, value.ToJson(), new DistributedCacheEntryOptions
                {
                    AbsoluteExpirationRelativeToNow = timeout
                });
            }
        }

        public string GetCache(string idKey)
        {
            if (idKey.IsNullOrEmpty())
            {
                return null;
            }
            string cacheKey = BuildKey(idKey);
            var cache = _cache.GetString(cacheKey);
            return cache;
        }
        public async Task<string> GetCacheAsync(string key)
        {
            if (key.IsNullOrEmpty())
            {
                return null;
            }
            string cacheKey = BuildKey(key);
            var cache = await _cache.GetStringAsync(cacheKey);
            return cache;
        }

        public T GetCache<T>(string key)
        {
            var cache = GetCache(key);
            if (!cache.IsNullOrEmpty())
            {
                return cache.ToObject<T>();
            }
            return default(T);
        }

        public async Task<T> GetCacheAsync<T>(string key)
        {
            var cache = await GetCacheAsync(key);
            if (!string.IsNullOrEmpty(cache))
            {
                return cache.ToObject<T>();
            }
            return default(T);
        }

        public void RemoveCache(string key)
        {
            _cache.Remove(BuildKey(key));
        }

        public async Task RemoveCacheAsync(string key)
        {
            await _cache.RemoveAsync(BuildKey(key));
        }

        public void RefreshCache(string key)
        {
            _cache.Refresh(BuildKey(key));
        }

        public async Task RefreshCacheAsync(string key)
        {
            await _cache.RefreshAsync(BuildKey(key));
        }

    }
}

CacheHelper 中,自定义了一个string的扩展方法ToObject<T>()ToObject<T>()扩展方法使用了 Newtonsoft.Json

/// <summary>
/// 将Json字符串反序列化为对象
/// </summary>
/// <typeparam name="T">对象类型</typeparam>
/// <param name="jsonStr">Json字符串</param>
/// <returns></returns>
public static T ToObject<T>(this string jsonStr)
{
    return JsonConvert.DeserializeObject<T>(jsonStr);
}

CacheHelper 的使用方法

安装Redis依赖

Redis依赖我使用的是Caching.CSRedis,安装依赖:

PM> Install-Package Caching.CSRedis -Version 3.6.90

配置appsettings.json

在appsettings.json中,对缓存进行配置:

 "Cache": {
    "CacheType": "Memory", // "Memory OR Redis"
    "RedisEndpoint": "127.0.0.1:6379" //Redis节点地址,定义详见 https://github.com/2881099/csredis
  },

如果要使用MemoryCache,CacheType就设置为Memory,如果要使用Redis,CacheType就设置为Redis。如果设置为Redis的话,还需要配置RedisEndpoint,保证Redis节点可用。

CacheOptions配置

编写一个名为CacheOptions的类。用于获取配置文件的配置节内容

namespace CacheHelper
{
    public class CacheOptions
    {
        public CacheType CacheType { get; set; }
        public string RedisEndpoint { get; set; }
    }
}

IHostBuilder扩展方法UseCache

编写一个IHostBuilder的扩展方法UseCache,用于注入MemoryCache或是Redis

public static IHostBuilder UseCache(this IHostBuilder hostBuilder)
{
    hostBuilder.ConfigureServices((buidlerContext, services) =>
    {
        var cacheOption = buidlerContext.Configuration.GetSection("Cache").Get<CacheOptions>();
        switch (cacheOption.CacheType)
        {
            case CacheType.Memory: services.AddDistributedMemoryCache(); break;
            case CacheType.Redis:
                {
                    var csredis = new CSRedisClient(cacheOption.RedisEndpoint);
                    RedisHelper.Initialization(csredis);
                    services.AddSingleton(csredis);
                    services.AddSingleton<IDistributedCache>(new CSRedisCache(RedisHelper.Instance));
                }; break;
            default: throw new Exception("缓存类型无效");
        }
    });

    return hostBuilder;
}

Program.cs中引用

var builder = WebApplication.CreateBuilder(args);
builder.Host.UseCache();

CacheHelper的使用。

public class HomeController
{
	readonly ICache _cache;
	public HomeController
	(
		ICache cache,
	)
	{
		_cache = cache;
	}
	
	public async Task CacheTest(string key)
	{
		string cache_value = "hello cache";
		//同步方法
		_cache.SetCache(key,cache_value );
		string v = _cache.GetCache<string>(key);
		_cache.RemoveCache(key);
		//异步方法
		await _cache.SetCacheAsync(key,cache_value );
		string val = await _cache.GetCacheAsync<string>(key);
		await _cache.RemoveCacheAsync(key);
	}
}

暂无,下次再会!


欢迎大家关注我的微信公众号,一起进步,一起成长
93324-20221205182127693-712634750.png

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK