// Admin.NET 项目的版æƒã€å•†æ ‡ã€ä¸“利和其他相关æƒåˆ©å‡å—ç›¸åº”æ³•å¾‹æ³•è§„çš„ä¿æŠ¤ã€‚ä½¿ç”¨æœ¬é¡¹ç›®åº”éµå®ˆç›¸å…³æ³•律法规和许å¯è¯çš„è¦æ±‚。 // // 本项目主è¦éµå¾ª MIT 许å¯è¯å’Œ Apache 许å¯è¯ï¼ˆç‰ˆæœ¬ 2.0)进行分å‘和使用。许å¯è¯ä½äºŽæºä»£ç æ ‘æ ¹ç›®å½•ä¸çš„ LICENSE-MIT å’Œ LICENSE-APACHE 文件。 // // ä¸å¾—利用本项目从事å±å®³å›½å®¶å®‰å…¨ã€æ‰°ä¹±ç¤¾ä¼šç§©åºã€ä¾µçŠ¯ä»–äººåˆæ³•æƒç›Šç‰æ³•å¾‹æ³•è§„ç¦æ¢çš„æ´»åЍï¼ä»»ä½•基于本项目二次开å‘è€Œäº§ç”Ÿçš„ä¸€åˆ‡æ³•å¾‹çº çº·å’Œè´£ä»»ï¼Œæˆ‘ä»¬ä¸æ‰¿æ‹…ä»»ä½•è´£ä»»ï¼ using NewLife.Reflection; using Newtonsoft.Json; namespace Admin.NET.Core.Service; /// <summary> /// ç³»ç»Ÿç¼“å˜æœåŠ¡ 🧩 /// </summary> [ApiDescriptionSettings(Order = 400)] public class SysCacheService : IDynamicApiController, ISingleton { private static ICacheProvider _cacheProvider; private readonly CacheOptions _cacheOptions; public SysCacheService(ICacheProvider cacheProvider, IOptions<CacheOptions> cacheOptions) { _cacheProvider = cacheProvider; _cacheOptions = cacheOptions.Value; } /// <summary> /// 申请分布å¼é” /// </summary> /// <param name="key">è¦é”定的key</param> /// <param name="msTimeout">申请é”ç‰å¾…的时间,å•使¯«ç§’</param> /// <param name="msExpire">é”过期时间,超过该时间没有主动是放则自动是放,必须整数秒,å•使¯«ç§’</param> /// <param name="throwOnFailure">å¤±è´¥æ—¶æ˜¯å¦æŠ›å‡ºå¼‚å¸¸,å¦‚ä¸æŠ›å‡ºå¼‚å¸¸ï¼Œå¯é€šè¿‡åˆ¤æ–返回null得知申请é”失败</param> /// <returns></returns> [DisplayName("申请分布å¼é”")] public IDisposable? BeginCacheLock(string key, int msTimeout = 500, int msExpire = 10000, bool throwOnFailure = true) { try { return _cacheProvider.Cache.AcquireLock(key, msTimeout, msExpire, throwOnFailure); } catch { return null; } } /// <summary> /// 获å–缓å˜é”®åé›†åˆ ðŸ”– /// </summary> /// <returns></returns> [DisplayName("获å–缓å˜é”®å集åˆ")] public List<string> GetKeyList() { return _cacheProvider.Cache == Cache.Default ? _cacheProvider.Cache.Keys.Where(u => u.StartsWith(_cacheOptions.Prefix)).Select(u => u[_cacheOptions.Prefix.Length..]).OrderBy(u => u).ToList() : ((FullRedis)_cacheProvider.Cache).Search($"{_cacheOptions.Prefix}*", int.MaxValue).Select(u => u[_cacheOptions.Prefix.Length..]).OrderBy(u => u).ToList(); } /// <summary> /// å¢žåŠ ç¼“å˜ /// </summary> /// <param name="key"></param> /// <param name="value"></param> /// <returns></returns> [NonAction] public bool Set(string key, object value) { if (string.IsNullOrWhiteSpace(key)) return false; return _cacheProvider.Cache.Set($"{_cacheOptions.Prefix}{key}", value); } /// <summary> /// å¢žåŠ ç¼“å˜å¹¶è®¾ç½®è¿‡æœŸæ—¶é—´ /// </summary> /// <param name="key"></param> /// <param name="value"></param> /// <param name="expire"></param> /// <returns></returns> [NonAction] public bool Set(string key, object value, TimeSpan expire) { if (string.IsNullOrWhiteSpace(key)) return false; return _cacheProvider.Cache.Set($"{_cacheOptions.Prefix}{key}", value, expire); } public async Task<TR> AdGetAsync<TR>(String cacheName, Func<Task<TR>> del, TimeSpan? expiry = default(TimeSpan?)) where TR : class { return await AdGetAsync<TR>(cacheName, del, new object[] { }, expiry); } public async Task<TR> AdGetAsync<TR, T1>(String cacheName, Func<T1, Task<TR>> del, T1 t1, TimeSpan? expiry = default(TimeSpan?)) where TR : class { return await AdGetAsync<TR>(cacheName, del, new object[] { t1 }, expiry); } public async Task<TR> AdGetAsync<TR, T1, T2>(String cacheName, Func<T1, T2, Task<TR>> del, T1 t1, T2 t2, TimeSpan? expiry = default(TimeSpan?)) where TR : class { return await AdGetAsync<TR>(cacheName, del, new object[] { t1, t2 }, expiry); } public async Task<TR> AdGetAsync<TR, T1, T2, T3>(String cacheName, Func<T1, T2, T3, Task<TR>> del, T1 t1, T2 t2, T3 t3, TimeSpan? expiry = default(TimeSpan?)) where TR : class { return await AdGetAsync<TR>(cacheName, del, new object[] { t1, t2, t3 }, expiry); } private async Task<T> AdGetAsync<T>(string cacheName, Delegate del, Object[] obs, TimeSpan? expiry) where T : class { var key = Key(cacheName, obs); // 使用分布å¼é” using (_cacheProvider.Cache.AcquireLock($@"lock:AdGetAsync:{cacheName}", 1000)) { var value = Get<T>(key); value ??= await ((dynamic)del).DynamicInvokeAsync(obs); Set(key, value); return value; } } public T Get<T>(String cacheName, object t1) { return Get<T>(cacheName, new object[] { t1 }); } public T Get<T>(String cacheName, object t1, object t2) { return Get<T>(cacheName, new object[] { t1, t2 }); } public T Get<T>(String cacheName, object t1, object t2, object t3) { return Get<T>(cacheName, new object[] { t1, t2, t3 }); } private T Get<T>(String cacheName, Object[] obs) { var key = cacheName + ":" + obs.Aggregate(string.Empty, (current, o) => current + $"<{o}>"); return Get<T>(key); } private static string Key(string cacheName, object[] obs) { foreach (var obj in obs) { if (obj is TimeSpan) { throw new Exception("缓å˜å‚数类型ä¸èƒ½èƒ½æ˜¯:TimeSpan类型"); } } StringBuilder sb = new StringBuilder(cacheName + ":"); foreach (var a in obs) { sb.Append($@"<{KeySingle(a)}>"); } return sb.ToString(); } public static string KeySingle(object t) { if (t.GetType().IsClass && !t.GetType().IsPrimitive) { return JsonConvert.SerializeObject(t); } return t?.ToString(); } /// <summary> /// 获å–缓å˜çš„å‰©ä½™ç”Ÿå˜æ—¶é—´ /// </summary> /// <param name="key"></param> /// <returns></returns> [NonAction] public TimeSpan GetExpire(string key) { return _cacheProvider.Cache.GetExpire(key); } /// <summary> /// 获å–ç¼“å˜ /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <returns></returns> [NonAction] public T Get<T>(string key) { return _cacheProvider.Cache.Get<T>($"{_cacheOptions.Prefix}{key}"); } /// <summary> /// åˆ é™¤ç¼“å˜ ðŸ”– /// </summary> /// <param name="key"></param> /// <returns></returns> [ApiDescriptionSettings(Name = "Delete"), HttpPost] [DisplayName("åˆ é™¤ç¼“å˜")] public int Remove(string key) { return _cacheProvider.Cache.Remove($"{_cacheOptions.Prefix}{key}"); } /// <summary> /// æ¸…ç©ºæ‰€æœ‰ç¼“å˜ ðŸ”– /// </summary> /// <returns></returns> [DisplayName("清空所有缓å˜")] [ApiDescriptionSettings(Name = "Clear"), HttpPost] public void Clear() { _cacheProvider.Cache.Clear(); Cache.Default.Clear(); } /// <summary> /// æ£€æŸ¥ç¼“å˜æ˜¯å¦å˜åœ¨ /// </summary> /// <param name="key">é”®</param> /// <returns></returns> [NonAction] public bool ExistKey(string key) { return _cacheProvider.Cache.ContainsKey($"{_cacheOptions.Prefix}{key}"); } /// <summary> /// æ ¹æ®é”®åå‰ç¼€åˆ é™¤ç¼“å˜ ðŸ”– /// </summary> /// <param name="prefixKey">é”®åå‰ç¼€</param> /// <returns></returns> [ApiDescriptionSettings(Name = "DeleteByPreKey"), HttpPost] [DisplayName("æ ¹æ®é”®åå‰ç¼€åˆ 除缓å˜")] public int RemoveByPrefixKey(string prefixKey) { var delKeys = _cacheProvider.Cache == Cache.Default ? _cacheProvider.Cache.Keys.Where(u => u.StartsWith($"{_cacheOptions.Prefix}{prefixKey}")).ToArray() : ((FullRedis)_cacheProvider.Cache).Search($"{_cacheOptions.Prefix}{prefixKey}*", int.MaxValue).ToArray(); return _cacheProvider.Cache.Remove(delKeys); } /// <summary> /// æ ¹æ®é”®åå‰ç¼€èŽ·å–é”®åé›†åˆ ðŸ”– /// </summary> /// <param name="prefixKey">é”®åå‰ç¼€</param> /// <returns></returns> [DisplayName("æ ¹æ®é”®åå‰ç¼€èŽ·å–é”®å集åˆ")] public List<string> GetKeysByPrefixKey(string prefixKey) { return _cacheProvider.Cache == Cache.Default ? _cacheProvider.Cache.Keys.Where(u => u.StartsWith($"{_cacheOptions.Prefix}{prefixKey}")).Select(u => u[_cacheOptions.Prefix.Length..]).ToList() : ((FullRedis)_cacheProvider.Cache).Search($"{_cacheOptions.Prefix}{prefixKey}*", int.MaxValue).Select(u => u[_cacheOptions.Prefix.Length..]).ToList(); } /// <summary> /// 获å–缓å˜å€¼ 🔖 /// </summary> /// <param name="key"></param> /// <returns></returns> [DisplayName("获å–缓å˜å€¼")] public object GetValue(string key) { // è‹¥Keyç»è¿‡URLç¼–ç 则进行解ç if (Regex.IsMatch(key, @"%[0-9a-fA-F]{2}")) key = HttpUtility.UrlDecode(key); return _cacheProvider.Cache == Cache.Default ? _cacheProvider.Cache.Get<object>($"{_cacheOptions.Prefix}{key}") : _cacheProvider.Cache.Get<string>($"{_cacheOptions.Prefix}{key}"); } /// <summary> /// èŽ·å–æˆ–æ·»åŠ ç¼“å˜ï¼ˆåœ¨æ•°æ®ä¸å˜åœ¨æ—¶æ‰§è¡Œå§”托请求数æ®ï¼‰ /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="callback"></param> /// <param name="expire">过期时间,å•ä½ç§’</param> /// <returns></returns> [NonAction] public T GetOrAdd<T>(string key, Func<string, T> callback, int expire = -1) { if (string.IsNullOrWhiteSpace(key)) return default; return _cacheProvider.Cache.GetOrAdd($"{_cacheOptions.Prefix}{key}", callback, expire); } /// <summary> /// HashåŒ¹é… /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <returns></returns> [NonAction] public IDictionary<String, T> GetHashMap<T>(string key) { return _cacheProvider.Cache.GetDictionary<T>(key); } /// <summary> /// æ‰¹é‡æ·»åŠ HASH /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="dic"></param> /// <returns></returns> [NonAction] public bool HashSet<T>(string key, Dictionary<string, T> dic) { var hash = GetHashMap<T>(key); foreach (var v in dic) { hash.Add(v); } return true; } /// <summary> /// æ·»åŠ ä¸€æ¡HASH /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="hashKey"></param> /// <param name="value"></param> [NonAction] public void HashAdd<T>(string key, string hashKey, T value) { var hash = GetHashMap<T>(key); hash.Add(hashKey, value); } /// <summary> /// æ·»åŠ æˆ–æ›´æ–°ä¸€æ¡HASH /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="hashKey"></param> /// <param name="value"></param> [NonAction] public void HashAddOrUpdate<T>(string key, string hashKey, T value) { var hash = GetHashMap<T>(key); if (hash.ContainsKey(hashKey)) { hash[hashKey] = value; } else hash.Add(hashKey, value); } /// <summary> /// 获å–多æ¡HASH /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="fields"></param> /// <returns></returns> [NonAction] public List<T> HashGet<T>(string key, params string[] fields) { var hash = GetHashMap<T>(key); return hash.Where(t => fields.Any(c => t.Key == c)).Select(t => t.Value).ToList(); } /// <summary> /// 获å–一æ¡HASH /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="field"></param> /// <returns></returns> [NonAction] public T HashGetOne<T>(string key, string field) { var hash = GetHashMap<T>(key); return hash.ContainsKey(field) ? hash[field] : default(T); } /// <summary> /// æ ¹æ®KEYèŽ·å–æ‰€æœ‰HASH /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <returns></returns> [NonAction] public IDictionary<string, T> HashGetAll<T>(string key) { var hash = GetHashMap<T>(key); return hash; } /// <summary> /// åˆ é™¤HASH /// </summary> /// <typeparam name="T"></typeparam> /// <param name="key"></param> /// <param name="fields"></param> /// <returns></returns> [NonAction] public int HashDel<T>(string key, params string[] fields) { var hash = GetHashMap<T>(key); fields.ToList().ForEach(t => hash.Remove(t)); return fields.Length; } ///// <summary> ///// æœç´¢HASH ///// </summary> ///// <typeparam name="T"></typeparam> ///// <param name="key"></param> ///// <param name="searchModel"></param> ///// <returns></returns> //[NonAction] //public List<KeyValuePair<string, T>> HashSearch<T>(string key, SearchModel searchModel) //{ // var hash = GetHashMap<T>(key); // return hash.Search(searchModel).ToList(); //} ///// <summary> ///// æœç´¢HASH ///// </summary> ///// <typeparam name="T"></typeparam> ///// <param name="key"></param> ///// <param name="pattern"></param> ///// <param name="count"></param> ///// <returns></returns> //[NonAction] //public List<KeyValuePair<string, T>> HashSearch<T>(string key, string pattern, int count) //{ // var hash = GetHashMap<T>(key); // return hash.Search(pattern, count).ToList(); //} }