Created
March 14, 2021 04:22
-
-
Save agehlot/d05ad67ca0dddadd89307ba302aa7d26 to your computer and use it in GitHub Desktop.
Sitecore custom cache class
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Sitecore.Caching; | |
using Sitecore.Data.Items; | |
using Sitecore.Diagnostics; | |
using System; | |
using System.Collections.Generic; | |
using System.Linq.Expressions; | |
namespace Core.Foundation.Caching.CustomCaching | |
{ | |
/// <summary> | |
/// Class CustomCache. | |
/// </summary> | |
public class CustomCache | |
{ | |
/// <summary> | |
/// The non publish key | |
/// </summary> | |
private const string NonPublishKey = "DontPublish-{0}"; | |
/// <summary> | |
/// The site key | |
/// </summary> | |
private const string SiteKey = "{0}-{1}-SiteCache"; | |
/// <summary> | |
/// The global key | |
/// </summary> | |
private const string GlobalKey = "Global"; | |
// The locking approach to keep the system from throwing threading issues | |
/// <summary> | |
/// The cache lock | |
/// </summary> | |
private static readonly object _cacheLock = new object(); | |
/// <summary> | |
/// The caching collection singleton to hold the caching references | |
/// </summary> | |
private static readonly Dictionary<string, ICache> CacheCollection = new Dictionary<string, ICache>(); | |
/// <summary> | |
/// The use custom cache | |
/// </summary> | |
private static readonly bool UseCustomCache = Sitecore.Configuration.Settings.GetBoolSetting("CustomCaching.Enabled", true); | |
/// <summary> | |
/// Gets the base key. | |
/// </summary> | |
/// <param name="isGlobal">if set to <c>true</c> [is global].</param> | |
/// <param name="siteName">Name of the site.</param> | |
/// <param name="databaseName">Name of the database.</param> | |
/// <returns>System.String.</returns> | |
private static string GetBaseKey(bool isGlobal = false, string siteName = "", string databaseName = "") | |
{ | |
// the site name can be overridden | |
if (string.IsNullOrEmpty(siteName)) | |
{ | |
siteName = Sitecore.Context.Site == null ? "NoSite" : Sitecore.Context.Site.Name; | |
} | |
// the database can be overridden | |
if (string.IsNullOrEmpty(databaseName)) | |
{ | |
databaseName = Sitecore.Context.Database == null ? "NoName" : Sitecore.Context.Database.Name; | |
} | |
// are we on the global cache | |
string cacheKey = string.Format(SiteKey, isGlobal ? GlobalKey : siteName, databaseName); | |
return cacheKey; | |
} | |
/// <summary> | |
/// The easy way to fetch the cache in a locked way | |
/// </summary> | |
/// <param name="isGlobal">Is Global</param> | |
/// <param name="siteName">Name of the site.</param> | |
/// <param name="databaseName">Name of the database.</param> | |
/// <returns>Returns the sitecore cache instance</returns> | |
public static ICache SitecoreCache(bool isGlobal = false, string siteName = "", string databaseName = "") | |
{ | |
// sets the default cache key | |
string cacheKey = GetBaseKey(isGlobal, siteName, databaseName); | |
ICache cache; | |
// we need to lock the cache due to multi threaded features | |
lock (_cacheLock) | |
{ | |
// data found | |
if (CacheCollection.ContainsKey(cacheKey)) | |
{ | |
// fetch the cache from the collection | |
cache = CacheCollection[cacheKey]; | |
} | |
else | |
{ | |
// fetches from the settings, but has a default size | |
cache = CacheManager.GetNamedInstance(cacheKey, Sitecore.StringUtil.ParseSizeString(Sitecore.Configuration.Settings.GetSetting("Caching.CacheSize", "100MB")), true); | |
try | |
{ | |
// add new reference to the singleton | |
CacheCollection.Add(cacheKey, cache); | |
} | |
catch (Exception ex) | |
{ | |
Log.Error("Error adding cacheKey " + cacheKey, ex, typeof(CustomCache)); | |
} | |
} | |
} | |
return cache; | |
} | |
/// <summary> | |
/// Gets the cached item. | |
/// </summary> | |
/// <typeparam name="T"></typeparam> | |
/// <param name="cacheKey">The cache key.</param> | |
/// <param name="globalCache">if set to <c>true</c> [global cache].</param> | |
/// <param name="siteName">Name of the site.</param> | |
/// <param name="databaseName">Name of the database.</param> | |
/// <returns>T.</returns> | |
public static T GetCachedItem<T>(string cacheKey, bool globalCache = false, string siteName = "", string databaseName = "") | |
{ | |
// no key so return error | |
if (string.IsNullOrEmpty(cacheKey)) | |
{ | |
return default(T); | |
} | |
object cachedItem = GetCachedItem(cacheKey, globalCache, siteName, databaseName); | |
if (cachedItem is T) | |
{ | |
return (T)cachedItem; | |
} | |
else | |
{ | |
return default(T); | |
} | |
} | |
/// <summary> | |
/// Gets the cached item. | |
/// </summary> | |
/// <param name="cacheKey">The cache key.</param> | |
/// <param name="globalCache">if set to <c>true</c> [global cache].</param> | |
/// <param name="siteName">Name of the site.</param> | |
/// <param name="databaseName">Name of the database.</param> | |
/// <returns>System.Object.</returns> | |
public static object GetCachedItem(string cacheKey, bool globalCache = false, string siteName = "", string databaseName = "") | |
{ | |
// no key so return error | |
if (string.IsNullOrEmpty(cacheKey)) | |
{ | |
return null; | |
} | |
object cachedItem = null; | |
// produce the valid key we want to use | |
string key = cacheKey.ToLower(); | |
// get the cache we are looking for | |
ICache cache = SitecoreCache(globalCache, siteName, databaseName); | |
if (cache != null) | |
{ | |
// make sure the system has the key before doing anything | |
if (cache.ContainsKey(key)) | |
{ | |
// get the data from the sitecore cache | |
cachedItem = cache[key]; | |
} | |
else | |
{ | |
// the item might be a non publish key | |
key = string.Format(NonPublishKey, key).ToLower(); | |
// get the data if found | |
if (cache.ContainsKey(key)) | |
{ | |
// get the data from the sitecore cache | |
cachedItem = cache[key]; | |
} | |
} | |
} | |
// return the data or null | |
return cachedItem; | |
} | |
/// <summary> | |
/// Determines whether the specified cache key contains key. | |
/// </summary> | |
/// <param name="cacheKey">The cache key.</param> | |
/// <param name="globalCache">if set to <c>true</c> [global cache].</param> | |
/// <param name="siteName">Name of the site.</param> | |
/// <param name="databaseName">Name of the database.</param> | |
/// <returns>System.Object.</returns> | |
public static object ContainsKey(string cacheKey, bool globalCache = false, string siteName = "", string databaseName = "") | |
{ | |
// no key so return error | |
if (string.IsNullOrEmpty(cacheKey)) | |
{ | |
return false; | |
} | |
// produce the valid key we want to use | |
string key = cacheKey.ToLower(); | |
// get the cache we are looking for | |
ICache cache = SitecoreCache(globalCache, siteName, databaseName); | |
return cache != null && cache.ContainsKey(cacheKey); | |
} | |
/// <summary> | |
/// Cacheds the value. | |
/// </summary> | |
/// <typeparam name="T"></typeparam> | |
/// <param name="cacheKey">The cache key.</param> | |
/// <param name="func">The function.</param> | |
/// <returns>T.</returns> | |
public static T CachedValue<T>(string cacheKey, Func<T> func = null) | |
{ | |
return CachedValue<T>(null, cacheKey, func); | |
} | |
/// <summary> | |
/// Cacheds the value. | |
/// </summary> | |
/// <typeparam name="T"></typeparam> | |
/// <param name="item">The item.</param> | |
/// <param name="func">The function.</param> | |
/// <returns>T.</returns> | |
public static T CachedValue<T>(Item item, Func<T> func = null) | |
{ | |
return CachedValue<T>(item, string.Empty, func); | |
} | |
/// <summary> | |
/// Cacheds the value. | |
/// </summary> | |
/// <typeparam name="T"></typeparam> | |
/// <param name="item">The item.</param> | |
/// <param name="cacheKey">The cache key.</param> | |
/// <param name="func">The function.</param> | |
/// <returns>T.</returns> | |
public static T CachedValue<T>(Item item, string cacheKey, Func<T> func = null) | |
{ | |
return CachedValue<T>(item == null ? Guid.Empty : item.ID.Guid, cacheKey, func); | |
} | |
/// <summary> | |
/// Cacheds the value. | |
/// </summary> | |
/// <typeparam name="T"></typeparam> | |
/// <param name="item">The item.</param> | |
/// <param name="cacheKey">The cache key.</param> | |
/// <param name="func">The function.</param> | |
/// <returns>T.</returns> | |
public static T CachedValue<T>(Guid item, string cacheKey, Func<T> func = null) | |
{ | |
var key = item + cacheKey; | |
var cachedData = GetCachedItem<T>(key); | |
if (!Equals(cachedData, default(T))) return cachedData; | |
if (func != null) | |
{ | |
cachedData = func.Invoke(); | |
} | |
cachedData = SaveCachedItem(key, cachedData); | |
return cachedData; | |
} | |
/// <summary> | |
/// Cacheds the value. | |
/// </summary> | |
/// <typeparam name="T"></typeparam> | |
/// <typeparam name="TU">The type of the tu.</typeparam> | |
/// <param name="item">The item.</param> | |
/// <param name="field">The field.</param> | |
/// <returns>T.</returns> | |
public static T CachedValue<T, TU>(TU item, Expression<Func<TU, T>> field) where TU : Item | |
{ | |
string cacheKey = string.Empty; | |
var ue = field.Body as UnaryExpression; | |
if (ue != null) | |
{ | |
var memberExpression = ue.Operand as MemberExpression; | |
if (memberExpression != null) | |
{ | |
cacheKey = memberExpression.Member.Name; | |
} | |
} | |
var body = field.Body as MemberExpression; | |
if (body != null) | |
{ | |
cacheKey = body.Member.Name; | |
} | |
if (string.IsNullOrWhiteSpace(cacheKey)) | |
{ | |
cacheKey = field.ToString(); | |
} | |
return string.IsNullOrWhiteSpace(cacheKey) ? | |
field.Compile()(item) : | |
CustomCache.CachedValue(item.ID.Guid, cacheKey, () => field.Compile()(item)); | |
} | |
/// <summary> | |
/// Saves the list to the cache, if html caching is enabled | |
/// </summary> | |
/// <typeparam name="T"></typeparam> | |
/// <param name="cacheKey">The unique key to save</param> | |
/// <param name="cachingData">The data to cache</param> | |
/// <param name="cacheTimer">The time we want to cache this data</param> | |
/// <param name="isNoSlidingExpiration">Is the cacheTimer an Absolute Expiration (default) or a sliding expiration</param> | |
/// <param name="globalCache">Is the data to be stored in the global cache or site specific cache</param> | |
/// <param name="removeOnPublish">Remove the contents on a publish, this is defaulted as true</param> | |
/// <param name="siteName">Force set the site name, if this is run from a scheduled task this should be set</param> | |
/// <param name="databaseName">Force the database if this is run from a scheduled tasks, this should be set</param> | |
/// <param name="cacheDep">Any caching dependencies for the cache. NOTE: Not valid for Sitecore Caching</param> | |
/// <param name="priority">The priority of the cache. NOTE: Not valid for Sitecore Caching</param> | |
/// <param name="callback">The call-back function of the cache. NOTE: Not valid for Sitecore Caching</param> | |
/// <returns>The object to be cached, regardless of if it was cached or caching is enabled.</returns> | |
/// . | |
public static T SaveCachedItem<T>(string cacheKey, T cachingData, | |
object cacheTimer = null, | |
bool isNoSlidingExpiration = true, | |
bool globalCache = false, | |
bool removeOnPublish = true, | |
string siteName = "", | |
string databaseName = "", | |
System.Web.Caching.CacheDependency cacheDep = null, | |
System.Web.Caching.CacheItemPriority priority = | |
System.Web.Caching.CacheItemPriority.Normal, | |
System.Web.Caching.CacheItemRemovedCallback callback = null) | |
{ | |
// make sure we have data and caching is enabled | |
if (string.IsNullOrWhiteSpace(cacheKey) || Equals(cachingData, default(T)) || Sitecore.Context.Site == null || !UseCustomCache) | |
return cachingData; | |
// set the key so we can override it | |
string key = cacheKey.ToLower(); | |
if (!removeOnPublish) | |
{ | |
key = string.Format(NonPublishKey, key).ToLower(); | |
} | |
ICache cache = SitecoreCache(globalCache, siteName, databaseName); | |
//Evict old data from cache | |
if (cache.ContainsKey(key)) | |
{ | |
cache.Remove(key); | |
} | |
if (cacheTimer == null) | |
{ | |
//Don't worry about the expiration | |
cache.Add(key.ToLower(), cachingData); | |
} | |
else | |
{ | |
// setup defaults for caching types | |
TimeSpan slidingCache = System.Web.Caching.Cache.NoSlidingExpiration; | |
DateTime absoluteCache = System.Web.Caching.Cache.NoAbsoluteExpiration; | |
// set the cache type | |
if (isNoSlidingExpiration) | |
{ | |
// make sure it's right | |
if (cacheTimer is DateTime) | |
{ | |
absoluteCache = (DateTime)cacheTimer; | |
} | |
else | |
{ | |
// we have an issue fix up | |
TimeSpan timeSpanCheck = (TimeSpan)cacheTimer; | |
absoluteCache = DateTime.Now.Add(timeSpanCheck); | |
} | |
} | |
else | |
{ | |
// make sure it's right | |
if (cacheTimer is TimeSpan) | |
{ | |
slidingCache = (TimeSpan)cacheTimer; | |
} | |
else | |
{ | |
// we have an issue fix up | |
DateTime dateCheck = (DateTime)cacheTimer; | |
slidingCache = dateCheck.Subtract(DateTime.Now); | |
} | |
} | |
// use the sitecore cache | |
cache.Add(key.ToLower(), cachingData, slidingCache, absoluteCache); | |
} | |
return cachingData; | |
} | |
/// <summary> | |
/// Removes the required item from the cache | |
/// </summary> | |
/// <param name="cacheKey">The cache key</param> | |
/// <param name="globalCache">Are we using the global cache</param> | |
/// <param name="siteName">The sitename</param> | |
/// <param name="databaseName">The database name</param> | |
/// <returns>Returns true if the data was removed from the cache or false if it wasnt or there was an error</returns> | |
public static bool RemoveCacheItem(string cacheKey, bool globalCache = false, string siteName = "", string databaseName = "") | |
{ | |
// no key so return error | |
if (string.IsNullOrEmpty(cacheKey)) | |
{ | |
return false; | |
} | |
// produce the valid key we want to use | |
string key = cacheKey.ToLower(); | |
// get the cache we are looking for | |
ICache cache = SitecoreCache(globalCache, siteName, databaseName); | |
if (cache != null) | |
{ | |
// make ure the system has the key before doing anything | |
if (cache.ContainsKey(key)) | |
{ | |
// remove the cached object | |
cache.Remove(key); | |
} | |
else | |
{ | |
// the item might be a non publish key | |
key = string.Format(NonPublishKey, key).ToLower(); | |
// get the data if found | |
if (cache.ContainsKey(key)) | |
{ | |
// remove the cached object | |
cache.Remove(key); | |
} | |
} | |
} | |
// data removed | |
return true; | |
} | |
/// <summary> | |
/// Clears the cache based on the details provided | |
/// </summary> | |
/// <param name="siteName">The name of the site to clear it's cached data</param> | |
/// <param name="databaseName">Name of the database.</param> | |
/// <param name="globalCache">Clear the global cache as well</param> | |
/// <param name="removeOnPublish">Remove the data which was indicated as not to be cleared when publishing</param> | |
public static void ClearCache(string siteName = "", string databaseName = "", bool globalCache = false, bool removeOnPublish = false) | |
{ | |
// get the cache from sitecore | |
ICache cache = SitecoreCache(globalCache, siteName, databaseName); | |
// make sure we have the data | |
if (cache == null) | |
{ | |
Log.Debug("Cache not found, looking for:" + siteName, typeof(CustomCache)); | |
return; | |
} | |
Log.Debug("Clearing Custom cache: " + cache.Name, typeof(CustomCache)); | |
// process the keys | |
foreach (string key in cache.GetCacheKeys()) | |
{ | |
// can we remove the item | |
if (removeOnPublish || !key.Contains("DontPublish-")) | |
{ | |
// remove the key | |
cache.Remove(key); | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment