#region Copyright (C) 2016 Kevin (OSS开源系列) 公众号:OSSCore /*************************************************************************** *   文件功能描述:全局插件 - 缓存插件辅助类 * *   创建人: Kevin * 创建人Email:1985088337@qq.com * * *****************************************************************************/ #endregion using System; using System.Threading.Tasks; namespace OSS.Tools.Cache { /// /// 缓存的辅助类 /// public static class CacheHelper { private static readonly DefaultToolCache defaultCache = new DefaultToolCache(); /// /// 缓存模块提供者 /// public static Func CacheProvider { get; set; } /// /// 通过模块名称获取 /// /// /// public static IToolCache GetCache(string cacheModule) { if (string.IsNullOrEmpty(cacheModule)) cacheModule = "default"; return CacheProvider?.Invoke(cacheModule) ?? defaultCache; } #region 缓存添加 /// /// 添加相对过期时间缓存,如果存在则更新 /// /// 添加缓存对象类型 /// 添加对象的key /// 值 /// 相对过期的TimeSpan /// 模块名称 /// 是否添加成功 [Obsolete("请使用 SetAsync")] public static bool Set(string key, T obj, TimeSpan slidingExpiration,string moduleName = "default") { return SetAsync(key, obj, slidingExpiration).Result; } /// /// 添加固定过期时间缓存,如果存在则更新 /// /// 添加缓存对象类型 /// 添加对象的key /// 值 /// 绝对过期时间 /// 模块名称 /// 是否添加成功 [Obsolete("请使用 SetAbsoluteAsync")] public static bool Set(string key, T obj, DateTime absoluteExpiration,string moduleName = "default") { return SetAbsoluteAsync(key,obj,TimeSpan.FromTicks((absoluteExpiration-DateTime.Now).Ticks)).Result; } /// /// 添加相对过期时间缓存,如果存在则更新 /// /// 添加缓存对象类型 /// 添加对象的key /// 值 /// 相对过期的TimeSpan /// 模块名称 /// 是否添加成功 public static Task SetAsync(string key, T obj, TimeSpan slidingExpiration, string moduleName = "default") { return SetAsync(key, obj, slidingExpiration, null, moduleName); } /// /// 添加固定过期时间缓存,如果存在则更新 /// /// 添加缓存对象类型 /// 添加对象的key /// 值 /// 绝对过期时间 /// 模块名称 /// 是否添加成功 public static Task SetAbsoluteAsync(string key, T obj, TimeSpan absoluteExpiration,string moduleName = "default") { return SetAsync(key, obj, null, absoluteExpiration, moduleName); } #endregion #region 缓存获取 /// /// 获取缓存对象 /// /// 获取缓存对象类型 /// key /// 模块名称 /// 获取指定key对应的值 [Obsolete("请使用 GetAsync")] public static T Get(string key, string moduleName = "default") { return GetAsync(key).Result; } /// /// 获取缓存对象 /// /// 获取缓存对象类型 /// key /// 模块名称 /// 获取指定key对应的值 public static Task GetAsync(string key, string moduleName = "default") { return GetCache(moduleName).GetAsync(key); } /// /// 获取缓存数据,如果没有则添加 /// /// /// key /// 如果不存在,通过此方法获取原始数据添加缓存 /// 过期时长,访问后自动延长 /// 模块名称 /// public static Task GetOrSetAsync(string cacheKey, Func> getFunc, TimeSpan slidingExpiration, string moduleName = "default") { return Get(cacheKey, getFunc, slidingExpiration, null, moduleName); } /// /// 获取缓存数据,如果没有则添加 /// /// /// key /// 没有数据时,通过此方法获取原始数据 /// 绝对过期时间 /// 模块名称 /// public static Task GetOrSetAbsoluteAsync(string cacheKey, Func> getFunc, TimeSpan absoluteExpiration, string moduleName = "default") { return Get(cacheKey, getFunc, null, absoluteExpiration, moduleName); } #endregion #region 缓存获取(击穿保护) /// /// 获取缓存数据【同时添加缓存击穿保护】,如果没有则添加 /// /// /// key /// 没有数据时,通过此方法获取原始数据 /// 过期时长(相对滚动时间),访问后自动延长 /// 缓存击穿保护触发条件 /// 缓存击穿保护秒数 /// 模块名称 /// public static Task GetOrSetAsync(string cacheKey, Func> getFunc,TimeSpan slidingExpiration, Func failProtectCondition, int protectSeconds = 10, string moduleName = "default") { return ProtectedGet(cacheKey, getFunc, slidingExpiration, null, failProtectCondition, protectSeconds, moduleName); } /// /// 获取缓存数据【同时添加缓存击穿保护】,如果没有则添加 /// /// /// key /// 如果不存在,通过此方法获取原始数据添加缓存 /// 绝对过期时间 /// 缓存击穿保护触发条件 /// 缓存击穿保护秒数 /// 模块名称 /// public static Task GetOrSetAbsoluteAsync(string cacheKey, Func> getFunc,TimeSpan absoluteExpiration, Func failProtectCondition, int protectSeconds = 10, string moduleName = "default") { return ProtectedGet(cacheKey, getFunc, TimeSpan.Zero, absoluteExpiration, failProtectCondition, protectSeconds, moduleName); } #endregion /// /// 移除缓存对象 /// /// /// 模块名称 /// 是否成功 public static Task RemoveAsync(string key, string moduleName = "default") { return GetCache(moduleName).RemoveAsync(key); } [Obsolete("请使用 RemoveAsync")] public static bool Remove(string key, string moduleName = "default") { return RemoveAsync(key).Result; } private static async Task Get(string cacheKey, Func> createFunc , TimeSpan? slidingExpiration, TimeSpan? absoluteExpiration, string moduleName) { var obj =await GetAsync(cacheKey); if (obj != null) return obj; if (createFunc == null) return default; var data = await createFunc.Invoke(); if (data == null) return default; await SetAsync(cacheKey, data, absoluteExpiration, slidingExpiration, moduleName); return data; } private static async Task ProtectedGet(string cacheKey, Func> getFunc , TimeSpan? slidingExpiration, TimeSpan? absoluteExpiration, Func hitProtectCondition, int hitProtectSeconds, string moduleName) { if (getFunc == null) throw new ArgumentNullException("获取原始数据方法(getFunc)不能为空!"); var obj = await GetAsync>(cacheKey); if (obj != null) return obj.Data; var data = await getFunc(); var hitTrigger = hitProtectCondition?.Invoke(data) ?? data == null; if (hitTrigger) { absoluteExpiration = TimeSpan.FromSeconds(hitProtectSeconds); slidingExpiration = null; } var cacheData = new ProtectCahceData(data); await SetAsync(cacheKey, cacheData, absoluteExpiration, slidingExpiration, moduleName); return data; } private static Task SetAsync(string key, T obj, TimeSpan? slidingExpiration, TimeSpan? absoluteExpiration, string moduleName = "default") { return GetCache(moduleName).SetAsync(key, obj, new CacheTimeOptions() { AbsoluteExpirationRelativeToNow = absoluteExpiration, SlidingExpiration = slidingExpiration , ModuleName = moduleName }); } } internal class ProtectCahceData { public ProtectCahceData(TT data) { Data = data; } public TT Data { get; } } }