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