namespace Kit.Helpers.Cache { using Microsoft.Extensions.Caching.Memory; using System; using System.Collections; using System.Collections.Generic; using System.Linq; public enum CacheLevels { None = 100, Database = 1, ClientFilter=3, Convert=5, ConvertFilter=7, Sorting=9, Paging=11 } public interface ICacheParameter { CacheLevels CachingLevel { get; } string GetCacheKey(CacheLevels cachingMode); bool IsCache(CacheLevels cachingMode); } public class CacheSetProperties { public bool EnableCaching { get; set; } public Int32 DurationSeconds { get; set; } public Int32 SlidingSeconds { get; set; } } public class CacheProvider : ICacheProvider { public Dictionary CacheCollection = new Dictionary(); private Dictionary LockObjects = new Dictionary(1000); private object m_keysLock = new object(); private IMemoryCache Cache; private object m_lock = new object(); public CacheProvider(IMemoryCache memoryCache) { Cache = memoryCache; } private IList GetCacheKeys() { var field = typeof(MemoryCache).GetProperty("EntriesCollection", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); var collection = field.GetValue(Cache) as ICollection; var items = new List(); if (collection != null) foreach (var item in collection) { var methodInfo = item.GetType().GetProperty("Key"); var val = methodInfo.GetValue(item); items.Add(val.ToString()); } return items; } public void PurgeCacheItem(string prefix, ICacheParameter parameters, CacheLevels cachingMode) { string cacheName = GetCacheKey(prefix, parameters, cachingMode); if (this.Cache != null) { //формируем список ключей для удаления из кэша List itemsToRemove = new List(); IList cacheKeys = this.GetCacheKeys(); foreach (string key in cacheKeys) { if (key.ToLowerEquals(cacheName)) { itemsToRemove.Add(key); } } //удаляем элементы кэша foreach (string key in itemsToRemove) { this.Cache.Remove(key); } } else { var itemToRemoveKeys = CacheCollection.Where(x => x.Key.ToLowerEquals(cacheName)).Select(x => x.Key); foreach (var key in itemToRemoveKeys) { lock (GetLockObject(key)) { CacheCollection.Remove(key); } lock (LockObjects) { LockObjects.Remove(key); } } } } public void PurgeCacheItems(string prefix) { prefix = prefix.ToLower(); if (this.Cache != null) { //формируем список ключей для удаления из кэша List itemsToRemove = new List(); IList cacheKeys = this.GetCacheKeys(); foreach (string key in cacheKeys) { if (key.ToLower().StartsWith(prefix)) { itemsToRemove.Add(key); } } //удаляем элементы кэша foreach (string key in itemsToRemove) { this.Cache.Remove(key); } } else { var itemToRemoveKeys = from di in CacheCollection where di.Key.ToLower().StartsWith(prefix) select di.Key; foreach (var key in itemToRemoveKeys) { lock (GetLockObject(key)) { CacheCollection.Remove(key); } lock (LockObjects) { LockObjects.Remove(key); } } } } public bool Contains(string cacheName) { if (this.Cache == null) return CacheCollection.ContainsKey(cacheName); return this.Cache.TryGetValue(cacheName, out object obj); } public void SetCacheData(string key, object data, CacheSetProperties setProperties) { if (setProperties.EnableCaching && data != null) { if (this.Cache == null) { if (CacheCollection.ContainsKey(key)) CacheCollection[key] = data; else CacheCollection.Add(key, data); } else { var cacheEntryOptions = new MemoryCacheEntryOptions() .SetSlidingExpiration(TimeSpan.FromSeconds(setProperties.SlidingSeconds)) .SetAbsoluteExpiration(TimeSpan.FromSeconds(setProperties.DurationSeconds)) .SetPriority(CacheItemPriority.Normal) //.SetSize(1024) ; this.Cache.Set(key, data, cacheEntryOptions); } } } public object GetCacheData(string cacheName) { if (Cache == null) { if (CacheCollection.ContainsKey(cacheName)) return CacheCollection[cacheName]; return null; } if (!this.Contains(cacheName)) { return null; } if (this.Cache.TryGetValue(cacheName, out object obj)) { return obj; } return null; } public object GetLockObject(string cacheName) { lock (m_keysLock) { if (!this.LockObjects.ContainsKey(cacheName)) this.LockObjects.Add(cacheName, new object()); return this.LockObjects[cacheName]; } } public delegate TResult GetData(); public TResult GetCacheData(string prefix, ICacheParameter parameters, CacheLevels cachingMode, Func getMethod) { CacheSetProperties setProperties = new CacheSetProperties{ EnableCaching = true, DurationSeconds = 6000, SlidingSeconds = 60 }; return GetCacheData(prefix, parameters, cachingMode, getMethod, setProperties); } public TResult GetCacheData(string prefix, ICacheParameter parameters, CacheLevels cachingMode, Func getMethod, CacheSetProperties setProperties) { object data = null; string cacheName = GetCacheKey(prefix, parameters, cachingMode); if (!cacheName.IsNullOrEmpty()) { data = GetCacheData(cacheName); if (data != null && data is TResult) return (TResult)data; lock (this.GetLockObject(cacheName)) { data = this.GetCacheData(cacheName); if (data == null) data = getMethod(); this.SetCacheData(cacheName, data, setProperties); } } else { data = getMethod(); } return (TResult)data; } public string GetCacheKey(string prefix, ICacheParameter parameters, CacheLevels cachingMode) { bool isCache = parameters != null && parameters.IsCache(cachingMode); return (isCache ? String.Format("{0}_{1}", prefix, parameters.GetCacheKey(cachingMode)) : String.Empty); } public void ClearCacheData(string key) { throw new NotImplementedException(); } public string CreateCacheName(object prefix, params object[] args) { throw new NotImplementedException(); } public void PurgeCacheItems(string cacheName, bool isPrefix = false) { throw new NotImplementedException(); } public void SetCacheData(string cacheName, TObject data, MemoryCacheEntryOptions setProperties = null) { throw new NotImplementedException(); } public TResult GetCacheData(string cacheName) { throw new NotImplementedException(); } public TResult GetCacheData(string cacheName, Func getMethod, MemoryCacheEntryOptions setProperties = null) { throw new NotImplementedException(); } public TResult GetCacheData(string cacheName, Func getMethod, MemoryCacheEntryOptions setProperties = null, PostEvictionDelegate callback = null) { throw new NotImplementedException(); } } }