#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; }
}
}