using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; using System.Web.Caching; using Umbraco.Core.Logging; namespace Umbraco.Core.Cache { /// /// A CacheProvider that wraps the logic of the HttpRuntime.Cache /// internal class HttpRuntimeCacheProvider : RuntimeCacheProviderBase { private readonly System.Web.Caching.Cache _cache; private static readonly object Locker = new object(); public HttpRuntimeCacheProvider(System.Web.Caching.Cache cache) { _cache = cache; } /// /// Clears everything in umbraco's runtime cache, which means that not only /// umbraco content is removed, but also other cache items from pages running in /// the same application / website. Use with care :-) /// public override void ClearAllCache() { var cacheEnumerator = _cache.GetEnumerator(); while (cacheEnumerator.MoveNext()) { _cache.Remove(cacheEnumerator.Key.ToString()); } } /// /// Clears the item in umbraco's runtime cache with the given key /// /// Key public override void ClearCacheItem(string key) { // NH 10 jan 2012 // Patch by the always wonderful Stéphane Gay to avoid cache null refs lock (Locker) { if (_cache[key] == null) return; _cache.Remove(key); ; } } /// /// Clears all objects in the System.Web.Cache with the System.Type name as the /// input parameter. (using [object].GetType()) /// /// The name of the System.Type which should be cleared from cache ex "System.Xml.XmlDocument" public override void ClearCacheObjectTypes(string typeName) { try { lock (Locker) { foreach (DictionaryEntry c in _cache) { if (_cache[c.Key.ToString()] != null && _cache[c.Key.ToString()].GetType().ToString().InvariantEquals(typeName)) { _cache.Remove(c.Key.ToString()); } } } } catch (Exception e) { LogHelper.Error("Cache clearing error", e); } } /// /// Clears all objects in the System.Web.Cache with the System.Type specified /// public override void ClearCacheObjectTypes() { try { lock (Locker) { foreach (DictionaryEntry c in _cache) { if (_cache[c.Key.ToString()] != null && _cache[c.Key.ToString()].GetType() == typeof(T)) { _cache.Remove(c.Key.ToString()); } } } } catch (Exception e) { LogHelper.Error("Cache clearing error", e); } } /// /// Clears all cache items that starts with the key passed. /// /// The start of the key public override void ClearCacheByKeySearch(string keyStartsWith) { foreach (DictionaryEntry c in _cache) { if (c.Key is string && ((string)c.Key).InvariantStartsWith(keyStartsWith)) { ClearCacheItem((string)c.Key); } } } /// /// Clears all cache items that have a key that matches the regular expression /// /// public override void ClearCacheByKeyExpression(string regexString) { foreach (DictionaryEntry c in _cache) { if (c.Key is string && Regex.IsMatch(((string)c.Key), regexString)) { ClearCacheItem((string)c.Key); } } } public override IEnumerable GetCacheItemsByKeySearch(string keyStartsWith) { return (from DictionaryEntry c in _cache where c.Key is string && ((string)c.Key).InvariantStartsWith(keyStartsWith) select c.Value.TryConvertTo() into attempt where attempt.Success select attempt.Result).ToList(); } /// /// Returns a cache item by key, does not update the cache if it isn't there. /// /// /// /// public override TT GetCacheItem(string cacheKey) { var result = _cache.Get(cacheKey); if (result == null) { return default(TT); } return result.TryConvertTo().Result; } /// /// Gets (and adds if necessary) an item from the cache with all of the default parameters /// /// /// /// /// public override TT GetCacheItem(string cacheKey, Func getCacheItem) { return GetCacheItem(cacheKey, CacheItemPriority.Normal, null, null, null, getCacheItem, Locker); } /// /// Gets (and adds if necessary) an item from the cache with the specified absolute expiration date (from NOW) /// /// /// /// This will set an absolute expiration from now until the timeout /// /// public override TT GetCacheItem(string cacheKey, TimeSpan? timeout, Func getCacheItem) { return GetCacheItem(cacheKey, null, timeout, getCacheItem); } /// /// Gets (and adds if necessary) an item from the cache with the specified absolute expiration date (from NOW) /// /// /// /// /// This will set an absolute expiration from now until the timeout /// /// public override TT GetCacheItem(string cacheKey, CacheItemRemovedCallback refreshAction, TimeSpan? timeout, Func getCacheItem) { return GetCacheItem(cacheKey, CacheItemPriority.Normal, refreshAction, timeout, getCacheItem); } /// /// Gets (and adds if necessary) an item from the cache with the specified absolute expiration date (from NOW) /// /// /// /// /// /// This will set an absolute expiration from now until the timeout /// /// public override TT GetCacheItem(string cacheKey, CacheItemPriority priority, CacheItemRemovedCallback refreshAction, TimeSpan? timeout, Func getCacheItem) { return GetCacheItem(cacheKey, priority, refreshAction, null, timeout, getCacheItem); } /// /// Gets (and adds if necessary) an item from the cache with the specified absolute expiration date (from NOW) /// /// /// /// /// /// /// This will set an absolute expiration from now until the timeout /// /// public override TT GetCacheItem(string cacheKey, CacheItemPriority priority, CacheItemRemovedCallback refreshAction, CacheDependency cacheDependency, TimeSpan? timeout, Func getCacheItem) { return GetCacheItem(cacheKey, priority, refreshAction, cacheDependency, timeout, getCacheItem, Locker); } /// /// Gets (and adds if necessary) an item from the cache with the specified absolute expiration date (from NOW) /// /// /// /// /// /// /// This will set an absolute expiration from now until the timeout /// /// /// private TT GetCacheItem(string cacheKey, CacheItemPriority priority, CacheItemRemovedCallback refreshAction, CacheDependency cacheDependency, TimeSpan? timeout, Func getCacheItem, object syncLock) { var result = _cache.Get(cacheKey); if (result == null) { lock (syncLock) { result = _cache.Get(cacheKey); if (result == null) { result = getCacheItem(); if (result != null) { //we use Insert instead of add if for some crazy reason there is now a cache with the cache key in there, it will just overwrite it. _cache.Insert(cacheKey, result, cacheDependency, timeout == null ? System.Web.Caching.Cache.NoAbsoluteExpiration : DateTime.Now.Add(timeout.Value), TimeSpan.Zero, priority, refreshAction); } } } } return result.TryConvertTo().Result; } /// /// Inserts an item into the cache, if it already exists in the cache it will be replaced /// /// /// /// /// public override void InsertCacheItem(string cacheKey, CacheItemPriority priority, Func getCacheItem) { InsertCacheItem(cacheKey, priority, null, null, null, getCacheItem); } /// /// Inserts an item into the cache, if it already exists in the cache it will be replaced /// /// /// /// /// This will set an absolute expiration from now until the timeout /// public override void InsertCacheItem(string cacheKey, CacheItemPriority priority, TimeSpan? timeout, Func getCacheItem) { InsertCacheItem(cacheKey, priority, null, null, timeout, getCacheItem); } /// /// Inserts an item into the cache, if it already exists in the cache it will be replaced /// /// /// /// /// /// This will set an absolute expiration from now until the timeout /// public override void InsertCacheItem(string cacheKey, CacheItemPriority priority, CacheDependency cacheDependency, TimeSpan? timeout, Func getCacheItem) { InsertCacheItem(cacheKey, priority, null, cacheDependency, timeout, getCacheItem); } /// /// Inserts an item into the cache, if it already exists in the cache it will be replaced /// /// /// /// /// /// /// This will set an absolute expiration from now until the timeout /// public override void InsertCacheItem(string cacheKey, CacheItemPriority priority, CacheItemRemovedCallback refreshAction, CacheDependency cacheDependency, TimeSpan? timeout, Func getCacheItem) { object result = getCacheItem(); if (result != null) { //we use Insert instead of add if for some crazy reason there is now a cache with the cache key in there, it will just overwrite it. _cache.Insert(cacheKey, result, cacheDependency, timeout == null ? System.Web.Caching.Cache.NoAbsoluteExpiration : DateTime.Now.Add(timeout.Value), TimeSpan.Zero, priority, refreshAction); } } } }