#region Copyright (C) 2016 Kevin (OSS开源系列) 公众号:OSSCore /*************************************************************************** *   文件功能描述:全局插件 - 缓存插件辅助类 * *   创建人: Kevin * 创建人Email:1985088337@qq.com * * *****************************************************************************/ #endregion namespace OSS.Tools.Cache { /// /// 缓存的辅助类 /// public static class CacheHelper { private static IToolCache DefaultCacheTool { get; set; } = new DefaultToolCache(); /// /// 缓存来源提供者 /// public static Func? CacheToolProvider { get; set; } /// /// 来源名称格式化 /// public static Func? SourceFormat { get; set; } /// /// 通过来源名称获取 /// /// /// public static IToolCache GetCache(string sourceName= "") { if (SourceFormat != null) sourceName = SourceFormat.Invoke(sourceName); return CacheToolProvider?.Invoke(sourceName) ?? DefaultCacheTool; } #region 缓存添加 /// /// 添加滚动过期缓存,如果存在则更新 /// /// 添加缓存对象类型 /// 添加对象的key /// 值 /// 滚动过期时长,访问后自动延长 /// 来源名称 /// 是否添加成功 public static Task SetAsync(string key, T obj, TimeSpan slidingExpiration, string sourceName = "") { return SetAsync(key, obj,new CacheTimeOptions(){sliding_expiration = slidingExpiration }, sourceName); } /// /// 添加固定过期时间缓存,如果存在则更新 /// /// 添加缓存对象类型 /// 添加对象的key /// 值 /// 固定过期时长,设置后到时过期 /// 来源名称 /// 是否添加成功 public static Task SetAbsoluteAsync(string key, T obj, TimeSpan absoluteExpiration, string sourceName = "") { return SetAsync(key, obj, new CacheTimeOptions(){absolute_expiration_relative_to_now = absoluteExpiration}, sourceName); } /// /// 设置缓存 /// /// /// 添加对象的key /// 值 /// 缓存过期时间选项 /// /// public static Task SetAsync(string key, T obj, CacheTimeOptions opt, string sourceName = "") { return GetCache(sourceName).SetAsync(key, obj, opt); } #endregion #region 缓存获取(简单) /// /// 获取缓存对象 /// /// 获取缓存对象类型 /// key /// 来源名称 /// 获取指定key对应的值 public static Task GetAsync(string key, string sourceName = "") { return GetCache(sourceName).GetAsync(key); } #endregion #region 缓存获取(击穿保护) /// /// 获取缓存数据,如果没有则添加 /// /// /// key /// 获取原始数据方法 /// 滚动过期时长,访问后自动延长 /// 缓存击穿保护秒数,默认值10。 /// 来源名称 /// public static Task GetOrSetAsync(string cacheKey, Func> getFunc, TimeSpan slidingExpiration, int hitProtectedSeconds = 10, string sourceName = "") { return GetOrSetAsync(cacheKey, getFunc, new CacheTimeOptions() { sliding_expiration = slidingExpiration }, null, hitProtectedSeconds, sourceName); } /// /// 获取缓存数据【同时添加缓存击穿保护】,如果没有则添加 /// /// /// key /// 获取原始数据方法 /// 滚动过期时长,访问后自动延长 /// 设置缓存前验证原始数据,false - 不满足设置缓存条件(会触发验证缓存击穿保护), true - 满足设置缓存条件 /// 缓存击穿保护秒数,默认值10。 /// 来源名称 /// public static Task GetOrSetAsync(string cacheKey, Func> getFunc,TimeSpan slidingExpiration, Func? beforeSettingChecker, int hitProtectedSeconds = 10, string sourceName = "") { return GetOrSetAsync(cacheKey, getFunc,new CacheTimeOptions(){sliding_expiration = slidingExpiration}, beforeSettingChecker, hitProtectedSeconds, sourceName); } /// /// 获取缓存数据【同时添加缓存击穿保护】,如果没有则添加 /// /// /// key /// 获取原始数据方法 /// 固定过期时长,设置后到时过期 /// 缓存击穿保护秒数,默认值10。 /// 来源名称 /// public static Task GetOrSetAbsoluteAsync(string cacheKey, Func> getFunc, TimeSpan absoluteExpiration, int hitProtectedSeconds = 10, string sourceName = "") { return GetOrSetAsync(cacheKey, getFunc, new CacheTimeOptions() { absolute_expiration_relative_to_now = absoluteExpiration }, null , hitProtectedSeconds, sourceName); } /// /// 获取缓存数据【同时添加缓存击穿保护】,如果没有则添加 /// /// /// key /// 获取原始数据方法 /// 固定过期时长,设置后到时过期 /// 设置缓存前验证原始数据,false - 不满足设置缓存条件(会触发验证缓存击穿保护), true - 满足设置缓存条件 /// 缓存击穿保护秒数,默认值10。 /// 来源名称 /// public static Task GetOrSetAbsoluteAsync(string cacheKey, Func> getFunc,TimeSpan absoluteExpiration, Func? beforeSettingChecker, int hitProtectedSeconds = 10,string sourceName = "") { return GetOrSetAsync(cacheKey, getFunc, new CacheTimeOptions(){absolute_expiration_relative_to_now = absoluteExpiration}, beforeSettingChecker, hitProtectedSeconds, sourceName); } /// /// 获取缓存数据,如果没有则添加 /// /// 数据类型 /// /// 获取原始数据方法 /// 缓存时间信息 /// 设置缓存前验证原始数据,false - 不满足设置缓存条件(会触发验证缓存击穿保护), true - 满足设置缓存条件 /// 缓存击穿保护秒数,默认值10。 /// 来源名称 /// public static async Task GetOrSetAsync(string cacheKey, Func> getFunc, CacheTimeOptions cacheTimeOpt, Func? beforeSettingChecker = null, int hitProtectedSeconds = 10, string sourceName = "") { if (getFunc == null) throw new ArgumentNullException("获取原始数据方法(getFunc)不能为空!"); var isProtected = hitProtectedSeconds > 0; if (isProtected) { var obj = await GetAsync>(cacheKey, sourceName); if (obj != null) return obj.data; } else { var obj = await GetAsync(cacheKey, sourceName); if (obj != null && !obj.Equals(default(RType))) return obj; } var data = await getFunc(); var checkRes = beforeSettingChecker == null ? (data != null && !data.Equals(default)) : beforeSettingChecker.Invoke(data); if (isProtected) { if (!checkRes) { cacheTimeOpt = new CacheTimeOptions() { absolute_expiration_relative_to_now = TimeSpan.FromSeconds(hitProtectedSeconds) }; } var cacheData = new ProtectCacheData(data); await SetAsync(cacheKey, cacheData, cacheTimeOpt, sourceName); return data; } if (checkRes) { await SetAsync(cacheKey, data, cacheTimeOpt, sourceName); } return data; } #endregion /// /// 移除缓存对象 /// /// /// 来源名称 /// 是否成功 public static Task RemoveAsync(string key, string sourceName = "") { return GetCache(sourceName).RemoveAsync(key); } /// /// 移除缓存对象 /// /// /// 来源名称 /// 是否成功 public static Task RemoveAsync(string[] keys, string sourceName = "") { return GetCache(sourceName).RemoveAsync(keys); } #region 过时方法 /// /// 获取缓存对象 /// /// 获取缓存对象类型 /// key /// 来源名称 /// 获取指定key对应的值 [Obsolete("请使用 GetAsync")] public static T Get(string key, string sourceName = "") { return GetAsync(key, sourceName).Result; } [Obsolete("请使用 RemoveAsync")] public static bool Remove(string key, string sourceName = "") { return RemoveAsync(key,sourceName).Result; } /// /// 添加滚动过期缓存,如果存在则更新 /// /// 添加缓存对象类型 /// 添加对象的key /// 值 /// 滚动过期时长,访问后自动延长 /// 来源名称 /// 是否添加成功 [Obsolete("请使用 SetAsync")] public static bool Set(string key, T obj, TimeSpan slidingExpiration, string sourceName = "") { return SetAsync(key, obj, slidingExpiration, sourceName).Result; } /// /// 添加固定过期时间缓存,如果存在则更新 /// /// 添加缓存对象类型 /// 添加对象的key /// 值 /// 固定过期时长,设置后到时过期 /// 来源名称 /// 是否添加成功 [Obsolete("请使用 SetAbsoluteAsync")] public static bool Set(string key, T obj, DateTime absoluteExpiration, string sourceName = "") { return SetAbsoluteAsync(key, obj, TimeSpan.FromTicks((absoluteExpiration - DateTime.Now).Ticks), sourceName).Result; } #region 缓存获取 /// /// 获取缓存数据,如果没有则添加 /// /// /// key /// 如果不存在,通过此方法获取原始数据添加缓存 /// 滚动过期时长,访问后自动延长 /// 来源名称 /// [Obsolete] public static Task GetOrSetAsync(string cacheKey, Func> getFunc, TimeSpan slidingExpiration, string sourceName) { return GetOrSetAsync(cacheKey, getFunc, new CacheTimeOptions() { sliding_expiration = slidingExpiration } , sourceName); } /// /// 获取缓存数据,如果没有则添加 /// /// /// key /// 没有数据时,通过此方法获取原始数据 /// 固定过期时长,设置后到时过期 /// 来源名称 /// [Obsolete] public static Task GetOrSetAbsoluteAsync(string cacheKey, Func> getFunc, TimeSpan absoluteExpiration, string sourceName) { return GetOrSetAsync(cacheKey, getFunc, new CacheTimeOptions() { absolute_expiration_relative_to_now = absoluteExpiration }, sourceName); } /// /// 获取缓存数据,如果没有则添加 /// /// /// /// 没有数据时,通过此方法获取原始数据 /// /// 来源名称 /// [Obsolete] public static async Task GetOrSetAsync(string cacheKey, Func> createFunc, CacheTimeOptions opt, string sourceName ) { var obj = await GetAsync(cacheKey, sourceName); if (obj != null && !obj.Equals(default(RType))) return obj; if (createFunc == null) return default; var data = await createFunc.Invoke(); if (data == null || data.Equals(default(RType))) return data; await SetAsync(cacheKey, data, opt, sourceName); return data; } #endregion #endregion } internal class ProtectCacheData { public ProtectCacheData(TT data) { this.data = data; } public TT data { get; } } }