#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 Func SourceFormat { get; set; } /// /// 通过来源名称获取 /// /// /// public static IToolCache GetCache(string sourceName= "default") { if (string.IsNullOrEmpty(sourceName)) sourceName = "default"; if (SourceFormat != null) sourceName = SourceFormat.Invoke(sourceName); return CacheProvider?.Invoke(sourceName) ?? defaultCache; } #region 缓存添加 /// /// 添加滚动过期缓存,如果存在则更新 /// /// 添加缓存对象类型 /// 添加对象的key /// 值 /// 滚动过期时长,访问后自动延长 /// 来源名称 /// 是否添加成功 public static Task SetAsync(string key, T obj, TimeSpan slidingExpiration, string sourceName = "default") { return SetAsync(key, obj,new CacheTimeOptions(){sliding_expiration = slidingExpiration }, sourceName); } /// /// 添加固定过期时间缓存,如果存在则更新 /// /// 添加缓存对象类型 /// 添加对象的key /// 值 /// 固定过期时长,设置后到时过期 /// 来源名称 /// 是否添加成功 public static Task SetAbsoluteAsync(string key, T obj, TimeSpan absoluteExpiration,string sourceName = "default") { 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 = "default") { return GetCache(sourceName).SetAsync(key, obj, opt); } #endregion #region 缓存获取(简单) /// /// 获取缓存对象 /// /// 获取缓存对象类型 /// key /// 来源名称 /// 获取指定key对应的值 public static Task GetAsync(string key, string sourceName = "default") { return GetCache(sourceName).GetAsync(key); } #endregion #region 缓存获取 /// /// 获取缓存数据,如果没有则添加 /// /// /// key /// 如果不存在,通过此方法获取原始数据添加缓存 /// 滚动过期时长,访问后自动延长 /// 来源名称 /// public static Task GetOrSetAsync(string cacheKey, Func> getFunc, TimeSpan slidingExpiration, string sourceName = "default") { return GetOrSetAsync(cacheKey, getFunc, new CacheTimeOptions() { sliding_expiration = slidingExpiration } , sourceName); } /// /// 获取缓存数据,如果没有则添加 /// /// /// key /// 没有数据时,通过此方法获取原始数据 /// 固定过期时长,设置后到时过期 /// 来源名称 /// public static Task GetOrSetAbsoluteAsync(string cacheKey, Func> getFunc, TimeSpan absoluteExpiration, string sourceName = "default") { return GetOrSetAsync(cacheKey, getFunc, new CacheTimeOptions() { absolute_expiration_relative_to_now = absoluteExpiration } , sourceName); } /// /// 获取缓存数据,如果没有则添加 /// /// /// /// 没有数据时,通过此方法获取原始数据 /// /// 来源名称 /// public static async Task GetOrSetAsync(string cacheKey, Func> createFunc , CacheTimeOptions opt, string sourceName = "default") { 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 #region 缓存获取(击穿保护) /// /// 获取缓存数据【同时添加缓存击穿保护】,如果没有则添加 /// /// /// key /// 没有数据时,通过此方法获取原始数据 /// 滚动过期时长,访问后自动延长 /// 缓存击穿保护触发条件 /// 缓存击穿保护秒数 /// 来源名称 /// public static Task GetOrSetAsync(string cacheKey, Func> getFunc,TimeSpan slidingExpiration, Func hitProtectedCondition, int protectedSeconds = 10, string sourceName = "default") { return GetOrSetAsync(cacheKey, getFunc,new CacheTimeOptions(){sliding_expiration = slidingExpiration}, hitProtectedCondition, protectedSeconds, sourceName); } /// /// 获取缓存数据【同时添加缓存击穿保护】,如果没有则添加 /// /// /// key /// 如果不存在,通过此方法获取原始数据添加缓存 /// 固定过期时长,设置后到时过期 /// 缓存击穿保护触发条件 /// 缓存击穿保护秒数 /// 来源名称 /// public static Task GetOrSetAbsoluteAsync(string cacheKey, Func> getFunc,TimeSpan absoluteExpiration, Func hitProtectedCondition, int protectedSeconds = 10,string sourceName = "default") { return GetOrSetAsync(cacheKey, getFunc, new CacheTimeOptions(){absolute_expiration_relative_to_now = absoluteExpiration}, hitProtectedCondition, protectedSeconds, sourceName); } /// /// 获取缓存数据【同时添加缓存击穿保护】,如果没有则添加 /// /// /// /// 没有数据时,通过此方法获取原始数据 /// 滚动过期时长,访问后自动延长,如果同时设置固定过期,则只能在固定时长范围内延长 /// 缓存击穿保护触发条件 /// 缓存击穿保护秒数 /// 来源名称 /// public static async Task GetOrSetAsync(string cacheKey, Func> getFunc , CacheTimeOptions cacheTimeOpt, Func hitProtectedCondition, int protectedSeconds=10, string sourceName = "default") { if (getFunc == null) throw new ArgumentNullException("获取原始数据方法(getFunc)不能为空!"); var obj = await GetAsync>(cacheKey, sourceName); if (obj != null) return obj.Data; var data = await getFunc(); var hitTrigger = hitProtectedCondition?.Invoke(data) ?? (data == null || data.Equals(default)); if (hitTrigger) { cacheTimeOpt = new CacheTimeOptions() { absolute_expiration_relative_to_now = TimeSpan.FromSeconds(protectedSeconds) }; } var cacheData = new ProtectCacheData(data); await SetAsync(cacheKey, cacheData, cacheTimeOpt, sourceName); return data; } #endregion /// /// 移除缓存对象 /// /// /// 来源名称 /// 是否成功 public static Task RemoveAsync(string key, string sourceName = "default") { return GetCache(sourceName).RemoveAsync(key); } /// /// 移除缓存对象 /// /// /// 来源名称 /// 是否成功 public static Task RemoveAsync(string[] keys, string sourceName = "default") { return GetCache(sourceName).RemoveAsync(keys); } #region 过时方法 /// /// 获取缓存对象 /// /// 获取缓存对象类型 /// key /// 来源名称 /// 获取指定key对应的值 [Obsolete("请使用 GetAsync")] public static T Get(string key, string sourceName = "default") { return GetAsync(key, sourceName).Result; } [Obsolete("请使用 RemoveAsync")] public static bool Remove(string key, string sourceName = "default") { return RemoveAsync(key,sourceName).Result; } /// /// 添加滚动过期缓存,如果存在则更新 /// /// 添加缓存对象类型 /// 添加对象的key /// 值 /// 滚动过期时长,访问后自动延长 /// 来源名称 /// 是否添加成功 [Obsolete("请使用 SetAsync")] public static bool Set(string key, T obj, TimeSpan slidingExpiration, string sourceName = "default") { return SetAsync(key, obj, slidingExpiration, sourceName).Result; } /// /// 添加固定过期时间缓存,如果存在则更新 /// /// 添加缓存对象类型 /// 添加对象的key /// 值 /// 固定过期时长,设置后到时过期 /// 来源名称 /// 是否添加成功 [Obsolete("请使用 SetAbsoluteAsync")] public static bool Set(string key, T obj, DateTime absoluteExpiration, string sourceName = "default") { return SetAbsoluteAsync(key, obj, TimeSpan.FromTicks((absoluteExpiration - DateTime.Now).Ticks), sourceName).Result; } #endregion } internal class ProtectCacheData { public ProtectCacheData(TT data) { Data = data; } public TT Data { get; } } }