.net系统缓存

.net系统缓存封装设计

缓存管理的接口ICache,可以用来保存键值对数据,设置缓存过期时间等功能,接口设计如下:

public interface ICache
{
        bool IsInitialized { get; }

        Task<Result> InitAsync(string connStr);

        Task<T> GetAsync<T>(string key, Func<T> defaultFunc = null, bool setDefault = false);

        Task<bool> SetAsync<T>(string key, T value, int expiredSeconds = 0);

        Task<bool> RemoveAsync(string key);

        Task<bool> ExistsAsync(string key);

        Task<long> SAddAsync<T>(string key, params T[] members);

        Task<long> SCountAsync(string key);

        Task<T[]> SMembersAsync<T>(string key);

        Task<bool> SIsMemberAsync<T>(string key, T member);

        Task<long> SRemoveAsync<T>(string key, params T[] members);

        /// <summary>
        /// 设置指定Key的过期时间
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="expiredSeconds">The expired seconds.</param>
        /// <returns>Task&lt;System.Boolean&gt;.</returns>
        Task<bool> SetExpireTimeAsync(string key, int expiredSeconds);
 }

服务端缓存采用Redis实现,具体实现如下:

internal class RedisCache : ICache
{
        private IRedisClient _client;

        private void CheckValid()
        {
            if (_client == null)
                throw new InvalidOperationException("RedisClient未初始化!");
        }

        public bool IsInitialized => _client != null;

        public async Task<Result> InitAsync(string connStr)
        {
            try
            {
                if (_client != null)
                    return Result.Ok;
                //connStr = "data source=127.0.0.1:6379;initial catalog=1";
                _client = await RedisClient.ConnectAsync(connStr, new RedisJsonSerializer());
                return Result.Ok;
            }
            catch (Exception e)
            {
                return new Result(e, "初始化Redis客户端失败!");
            }
        }

        public void ClearCache()
        {
            _client?.FlushDbAsync().Wait();
        }

        public async Task<T> GetAsync<T>(string key, Func<T> defaultFunc = null, bool setDefault = false)
        {
            CheckValid();
            try
            {
                var bulk = await _client.GetAsync(key);
                if (!bulk.IsNull)
                    return bulk.As<T>();
            }
            catch
            {
                //ignore
            }
            if (defaultFunc == null)
                throw new KeyNotFoundException($"Redis中值为{key}的键不存在,或值不是{typeof(T)}");
            var value = defaultFunc();
            if (setDefault)
                await SetAsync(key, value, 0);
            return value;
        }

        public async Task<bool> SetAsync<T>(string key, T value, int expiredSeconds)
        {
            CheckValid();
            string result;
            if (expiredSeconds > 0)
                result = await _client.SetExAsync(key, expiredSeconds, value);
            else
                result = await _client.SetAsync(key, value);
            return result == "OK";
        }

        public async Task<bool> RemoveAsync(string key)
        {
            CheckValid();
            var r = await _client.DelAsync(key);
            return r == 1;
        }

        public async Task<bool> ExistsAsync(string key)
        {
            CheckValid();
            var r = await _client.ExistsAsync(key);
            return r == 1;
        }

        public async Task<long> SAddAsync<T>(string key, params T[] members)
        {
            CheckValid();
            var r = await _client.SAddAsync(key, members);
            return r;
        }

        public async Task<long> SCountAsync(string key)
        {
            CheckValid();
            var r = await _client.SCardAsync(key);
            return r;
        }

        public async Task<T[]> SMembersAsync<T>(string key)
        {
            CheckValid();
            var r = await _client.SMembersAsync(key);
            return r.AsArray<T>();
        }

        public async Task<bool> SIsMemberAsync<T>(string key, T member)
        {
            CheckValid();
            var r = await _client.SIsMemberAsync(key, member);
            return r == 1;
        }

        public async Task<long> SRemoveAsync<T>(string key, params T[] members)
        {
            CheckValid();
            var r = await _client.SRemAsync(key, members);
            return r;
        }

        public async Task<long> HCountAsync(string key)
        {
            CheckValid();
            return await _client.HLenAsync(key);
        }

        public async Task<T> HGetAsync<T>(string key, string field, Func<T> defaultFunc = null)
        {
            CheckValid();
            var r = await _client.HExistsAsync(key, field);
            if (r == 1)
            {
                try
                {
                    var bulk = await _client.HGetAsync(key, field);
                    if (!bulk.IsNull)
                        return bulk.As<T>();
                }
                catch
                {
                    //ignore
                }
            }
            if (defaultFunc == null)
                throw new KeyNotFoundException($"Redis中值为{key}-{field}的键不存在,或值不是{typeof(T)}");
            return defaultFunc();
        }

        public async Task HSetAsync<T>(string key, string field, T value)
        {
            CheckValid();
            await _client.HSetAsync(key, field, value);
        }

        public async Task<bool> HRemoveAsync(string key, string field)
        {
            CheckValid();
            var count = await _client.HDelAsync(key, field);
            return count == 1;
        }

        public async Task HRemoveAsync(string key, string[] fields)
        {
            CheckValid();
            await _client.HDelAsync(key, fields);
        }

        public async Task<bool> HExistsAsync(string key, string field)
        {
            CheckValid();
            return await _client.HExistsAsync(key, field) == 1;
        }

        public async Task<string[]> HKeysAsync(string key)
        {
            CheckValid();
            var bulk = await _client.HKeysAsync(key);
            return bulk.IsNull ? new string[0] : bulk.AsArray<string>();
        }

        public async Task<KeyValuePair<string, T>[]> HAllAsync<T>(string key)
        {
            CheckValid();
            var bulk = await _client.HGetAllAsync(key);
            if (bulk.IsNull)
                return new KeyValuePair<string, T>[0];
            var values = bulk.AsArray<string>();
            var results = new KeyValuePair<string, T>[values.Length / 2];
            for (var i = 0; i < values.Length; i += 2)
            {
                var k = values[i];
                var v = values[i + 1].As<T>();
                results[i / 2] = new KeyValuePair<string, T>(k, v);
            }
            return results;
        }

        public async Task<bool> SetExpireTimeAsync(string key, int expiredSeconds)
        {
            CheckValid();
            if (expiredSeconds < 0)
                return false;
            var r = await _client.ExpireAsync(key, expiredSeconds);
            return r == 1;
        }
 }

CS及MS端的缓存采用Akavache实现,具体实现如下:

internal partial class Cache : ICache
{
		public bool IsInitialized => true;

		public Task<Result> InitAsync(string connStr)
		{
			return Task.FromResult(Result.Ok);
		}

		public async Task<T> GetAsync<T>(string key, Func<T> defaultFunc = null, bool setDefault = false)
		{
			try
			{
				return await BlobCache.LocalMachine.GetObject<T>(key);
			}
			catch (Exception)
			{
				if (defaultFunc == null)
					throw;
			}
			var value = defaultFunc();
			if (setDefault)
				await SetAsync(key, value);
			return value;
		}

		public async Task<bool> SetAsync<T>(string key, T value, int expiredSeconds = 0)
		{
			try
			{
				DateTimeOffset? offset = null;
				if (expiredSeconds > 0)
					offset = new DateTimeOffset(DateTime.Now.AddSeconds(expiredSeconds));
				await BlobCache.LocalMachine.InsertObject(key, value, offset);
				return true;
			}
			catch
			{
				return false;
			}
		}

		public async Task<bool> RemoveAsync(string key)
		{
			try
			{
				await BlobCache.LocalMachine.Invalidate(key);
				return true;
			}
			catch
			{
				return false;
			}
		}

		public async Task<bool> ExistsAsync(string key)
		{
			try
			{
				await BlobCache.LocalMachine.Get(key);
				return true;
			}
			catch (Exception)
			{
				return false;
			}
		}

		public async Task<long> SAddAsync<T>(string key, params T[] members)
		{
			var set = await GetAsync(key, () => new HashSet<string>(), true);
			var c1 = set.Count;
			set.AddRange(members.Select(t => JsonConvert.SerializeObject(t)));
			if (await SetAsync(key, set))
				return set.Count - c1;
			return -1;
		}

		public async Task<long> SCountAsync(string key)
		{
			try
			{
				var col = await GetAsync<IEnumerable<object>>(key);
				return col.Count();
			}
			catch (Exception)
			{
				return 0;
			}
		}

		public async Task<T[]> SMembersAsync<T>(string key)
		{
			var set = await GetAsync(key, () => new HashSet<string>());
			return set.Select(JsonConvert.DeserializeObject<T>).ToArray();
		}

		public async Task<bool> SIsMemberAsync<T>(string key, T member)
		{
			var set = await GetAsync(key, () => new HashSet<string>());
			var mem = JsonConvert.SerializeObject(member);
			return set.Contains(mem);
		}

		public async Task<long> SRemoveAsync<T>(string key, params T[] members)
		{
			var set = await GetAsync(key, () => new HashSet<string>());
			if (set.Count == 0)
				return 0;
			var count = 0;
			foreach (var member in members)
			{
				var mem = JsonConvert.SerializeObject(member);
				if (set.Remove(mem))
					count++;
			}
			if (await SetAsync(key, set))
				return count;
			return -1;
		}

		public async Task<bool> SetExpireTimeAsync(string key, int expiredSeconds)
		{
			if (expiredSeconds <= 0)
				return false;
			try
			{
				var data = await BlobCache.LocalMachine.Get(key);
				DateTimeOffset? offset = null;
				if (expiredSeconds > 0)
					offset = new DateTimeOffset(DateTime.Now.AddSeconds(expiredSeconds));
				await BlobCache.LocalMachine.Insert(key, data, offset);
				return true;
			}
			catch (Exception e)
			{
				Mg.Get<IMgLog>().Error($"设置缓存过期时间失败:key={key},expiredSeconds={expiredSeconds}", e);
				return false;
			}
		}
}
原文地址:https://www.cnblogs.com/ghhjanes/p/11208775.html