Redis help class

1. 先创建缓存接口

/// <summary>
    /// 缓存接口
    /// </summary>
    public interface ICacheRepository : IDisposable
    {
        /// <summary>
        /// Get a cached item. If it's not in the cache yet, then load and cache it
        /// </summary>
        /// <typeparam name="T">Type of cached item</typeparam>
        /// <param name="key">Cache key</param>
        /// <param name="acquire">Function to load item if it's not in the cache yet</param>
        /// <returns>The cached value associated with the specified key</returns>
        T Get<T>(CacheKey key, Func<T> acquire) where T: class;

        /// <summary>
        /// Get a cached item. If it's not in the cache yet, then load and cache it
        /// </summary>
        /// <typeparam name="T">Type of cached item</typeparam>
        /// <param name="key">Cache key</param>
        /// <param name="acquire">Function to load item if it's not in the cache yet</param>
        /// <returns>The cached value associated with the specified key</returns>
        Task<T> GetAsync<T>(CacheKey key, Func<Task<T>> acquire) where T : class;

        /// <summary>
        /// Removes the value with the specified key from the cache
        /// </summary>
        /// <param name="key">Key of cached item</param>
        void Remove(CacheKey key);

        /// <summary>
        /// Adds the specified key and object to the cache
        /// </summary>
        /// <param name="key">Key of cached item</param>
        /// <param name="data">Value for caching</param>
        void Set(CacheKey key, object data);

        /// <summary>
        /// Gets a value indicating whether the value associated with the specified key is cached
        /// </summary>
        /// <param name="key">Key of cached item</param>
        /// <returns>True if item already is in cache; otherwise false</returns>
        bool IsSet(CacheKey key);

        /// <summary>
        /// Removes items by key prefix
        /// </summary>
        /// <param name="prefix">String key prefix</param>
        void RemoveByPrefix(string prefix);

        /// <summary>
        /// Clear all cache data
        /// </summary>
        void Clear();
    }

2. redis类

public class RedisCacheRepository : ICacheRepository
    {
        private bool _disposed;
        private readonly ILogger<RedisCacheRepository> _logger;
        private readonly ConnectionMultiplexer _redis;
        private readonly IDatabase _db;
        private readonly CacheOptions _cacheOptions;

        public RedisCacheRepository(
            ILogger<RedisCacheRepository> logger, 
            ConnectionMultiplexer redis, 
            IOptions<CacheOptions> cacheOptions)
        {
            _logger = logger;
            _redis = redis;
            _db = redis.GetDatabase();
            _cacheOptions = cacheOptions.Value;
        }

        #region Utilities

        /// <summary>
        /// Gets the list of cache keys prefix
        /// </summary>
        /// <param name="endPoint">Network address</param>
        /// <param name="prefix">String key pattern</param>
        /// <returns>List of cache keys</returns>
        protected virtual IEnumerable<RedisKey> GetKeys(EndPoint endPoint, string prefix = null)
        {
            var server = _redis.GetServer(endPoint);

            //we can use the code below (commented), but it requires administration permission - ",allowAdmin=true"
            //server.FlushDatabase();

            var keys = server.Keys(_db.Database, string.IsNullOrEmpty(prefix) ? null : $"{prefix}*");

            //we should always persist the data protection key list
            keys = keys.Where(key => !key.ToString().Equals(_cacheOptions.RedisDataProtectionKey,
                StringComparison.OrdinalIgnoreCase));

            return keys;
        }

        /// <summary>
        /// Gets the value associated with the specified key.
        /// </summary>
        /// <typeparam name="T">Type of cached item</typeparam>
        /// <param name="key">Key of cached item</param>
        /// <returns>The cached value associated with the specified key</returns>
        protected virtual async Task<T> GetAsync<T>(CacheKey key) where T : class
        {
            //get serialized item from cache
            var serializedItem = await _db.StringGetAsync(key.Key);
            if (!serializedItem.HasValue)
                return default;

            //deserialize item
            var item = JsonHelper.DeserializeJsonToObject<T>(serializedItem);
            if (item == null)
                return default;

            return item;
        }

        /// <summary>
        /// Adds the specified key and object to the cache
        /// </summary>
        /// <param name="key">Key of cached item</param>
        /// <param name="data">Value for caching</param>
        /// <param name="cacheTime">Cache time in minutes</param>
        protected virtual async Task SetAsync(string key, object data, int cacheTime)
        {
            if (data == null)
                return;

            //set cache time
            var expiresIn = TimeSpan.FromMinutes(cacheTime);

            //serialize item
            var serializedItem = JsonHelper.SerializeObject(data);

            //and set it to cache
            await _db.StringSetAsync(key, serializedItem, expiresIn);
        }

        /// <summary>
        /// Gets a value indicating whether the value associated with the specified key is cached
        /// </summary>
        /// <param name="key">Key of cached item</param>
        /// <returns>True if item already is in cache; otherwise false</returns>
        protected virtual async Task<bool> IsSetAsync(CacheKey key)
        {
            return await _db.KeyExistsAsync(key.Key);
        }

        /// <summary>
        /// Attempts to execute the passed function and ignores the RedisTimeoutException if specified by settings
        /// </summary>
        /// <typeparam name="T">Type of item which returned by the action</typeparam>
        /// <param name="action">The function to be tried to perform</param>
        /// <returns>(flag indicates whether the action was executed without error, action result or default value)</returns>
        protected virtual (bool, T) TryPerformAction<T>(Func<T> action)
        {
            try
            {
                //attempts to execute the passed function
                var rez = action();

                return (true, rez);
            }
            catch (RedisTimeoutException)
            {
                //ignore the RedisTimeoutException if specified by settings
                if (_cacheOptions.IgnoreRedisTimeoutException)
                    return (false, default);

                //or rethrow the exception
                throw;
            }
        }

        #endregion

        #region Methods

        /// <summary>
        /// Get a cached item. If it's not in the cache yet, then load and cache it
        /// </summary>
        /// <typeparam name="T">Type of cached item</typeparam>
        /// <param name="key">Cache key</param>
        /// <param name="acquire">Function to load item if it's not in the cache yet</param>
        /// <returns>The cached value associated with the specified key</returns>
        public async Task<T> GetAsync<T>(CacheKey key, Func<Task<T>> acquire) where T: class
        {
            //item already is in cache, so return it
            if (await IsSetAsync(key))
                return await GetAsync<T>(key);

            //or create it using passed function
            var result = await acquire();

            //and set in cache (if cache time is defined)
            if (key.CacheTime > 0)
                await SetAsync(key.Key, result, key.CacheTime);

            return result;
        }

        /// <summary>
        /// Gets or sets the value associated with the specified key.
        /// </summary>
        /// <typeparam name="T">Type of cached item</typeparam>
        /// <param name="key">Key of cached item</param>
        /// <returns>The cached value associated with the specified key</returns>
        public virtual T Get<T>(CacheKey key) where T: class
        {
            var (_, rez) = TryPerformAction(() =>
            {
                var serializedItem = _db.StringGet(key.Key);
                if (!serializedItem.HasValue)
                    return default;

                //deserialize item
                var item = JsonHelper.DeserializeJsonToObject<T>(serializedItem);
                return item ?? default;
            });

            return rez;
        }

        /// <summary>
        /// Get a cached item. If it's not in the cache yet, then load and cache it
        /// </summary>
        /// <typeparam name="T">Type of cached item</typeparam>
        /// <param name="key">Cache key</param>
        /// <param name="acquire">Function to load item if it's not in the cache yet</param>
        /// <returns>The cached value associated with the specified key</returns>
        public virtual T Get<T>(CacheKey key, Func<T> acquire) where T : class
        {
            //item already is in cache, so return it
            if (IsSet(key))
            {
                var rez = Get<T>(key);

                if (rez != null && !rez.Equals(default(T)))
                    return rez;
            }

            //or create it using passed function
            var result = acquire();

            //and set in cache (if cache time is defined)
            if (key.CacheTime > 0)
                Set(key, result);

            return result;
        }

        /// <summary>
        /// Adds the specified key and object to the cache
        /// </summary>
        /// <param name="key">Key of cached item</param>
        /// <param name="data">Value for caching</param>
        public virtual void Set(CacheKey key, object data)
        {
            if (data == null)
                return;

            //set cache time
            var expiresIn = TimeSpan.FromMinutes(key.CacheTime);

            //serialize item
            var serializedItem = JsonHelper.SerializeObject(data);

            //and set it to cache
            TryPerformAction(() => _db.StringSet(key.Key, serializedItem, expiresIn));
        }

        /// <summary>
        /// Gets a value indicating whether the value associated with the specified key is cached
        /// </summary>
        /// <param name="key">Key of cached item</param>
        /// <returns>True if item already is in cache; otherwise false</returns>
        public virtual bool IsSet(CacheKey key)
        {
            var (flag, rez) = TryPerformAction(() => _db.KeyExists(key.Key));

            return flag && rez;
        }

        /// <summary>
        /// Removes the value with the specified key from the cache
        /// </summary>
        /// <param name="key">Key of cached item</param>
        public virtual void Remove(CacheKey key)
        {
            //we should always persist the data protection key list
            if (key.Key.Equals(_cacheOptions.RedisDataProtectionKey, StringComparison.OrdinalIgnoreCase))
                return;
            //remove item from caches
            TryPerformAction(() => _db.KeyDelete(key.Key));
        }

        /// <summary>
        /// Removes items by key prefix
        /// </summary>
        /// <param name="prefix">String key prefix</param>
        public virtual void RemoveByPrefix(string prefix)
        {
            foreach (var endPoint in _redis.GetEndPoints())
            {
                var keys = GetKeys(endPoint, prefix);

                TryPerformAction(() => _db.KeyDelete(keys.ToArray()));
            }
        }

        /// <summary>
        /// Clear all cache data
        /// </summary>
        public virtual void Clear()
        {
            foreach (var endPoint in _redis.GetEndPoints())
            {
                var keys = GetKeys(endPoint).ToArray();

                TryPerformAction(() => _db.KeyDelete(keys.ToArray()));
            }
        }

        /// <summary>
        /// Dispose cache manager
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        // Protected implementation of Dispose pattern.
        protected virtual void Dispose(bool disposing)
        {
            if (_disposed)
                return;

            _disposed = true;
        }

        #endregion
    }

 

posted @ 2021-11-29 17:16  sunshine静  阅读(33)  评论(0编辑  收藏  举报