// -------------------------------------------------------------------------------------------------------------------- // // Copyright (c) James South. // Licensed under the Apache License, Version 2.0. // // // Encapsulates methods that allow the caching and retrieval of objects from the in memory cache. // // -------------------------------------------------------------------------------------------------------------------- namespace ImageProcessor.Web.Caching { using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Runtime.Caching; /// /// Encapsulates methods that allow the caching and retrieval of objects from the in memory cache. /// internal static class MemCache { /// /// The cache /// private static readonly ObjectCache Cache = MemoryCache.Default; /// /// An internal list of cache keys to allow bulk removal. /// private static readonly ConcurrentDictionary CacheItems = new ConcurrentDictionary(); /// /// Adds an item to the cache. /// /// /// A unique identifier for the cache entry. /// /// /// The object to insert. /// /// /// Optional. An object that contains eviction details for the cache entry. This object /// provides more options for eviction than a simple absolute expiration. The default value for the optional parameter /// is null. /// /// /// Optional. A named region in the cache to which the cache entry can be added, /// if regions are implemented. The default value for the optional parameter /// is null. /// /// /// True if the insertion try succeeds, or false if there is an already an entry /// in the cache with the same key as key. /// public static bool AddItem(string key, object value, CacheItemPolicy policy = null, string regionName = null) { bool isAdded; lock (Cache) { if (policy == null) { // Create a new cache policy with the default values policy = new CacheItemPolicy(); } try { Cache.Set(key, value, policy, regionName); isAdded = true; } catch { isAdded = false; } if (isAdded) { CacheItems[key] = regionName; } } return isAdded; } /// /// Fetches an item matching the given key from the cache. /// /// /// A unique identifier for the cache entry. /// /// /// Optional. A named region in the cache to which the cache entry can be added, /// if regions are implemented. The default value for the optional parameter /// is null. /// /// /// The cache entry that is identified by key. /// public static object GetItem(string key, string regionName = null) { lock (Cache) { return Cache.Get(key, regionName); } } /// /// Updates an item to the cache. /// /// /// A unique identifier for the cache entry. /// /// /// The object to insert. /// /// /// Optional. An object that contains eviction details for the cache entry. This object /// provides more options for eviction than a simple absolute expiration. The default value for the optional parameter /// is null. /// /// /// Optional. A named region in the cache to which the cache entry can be added, /// if regions are implemented. The default value for the optional parameter /// is null. /// /// /// True if the update try succeeds, or false if there is an already an entry /// in the cache with the same key as key. /// public static bool UpdateItem(string key, object value, CacheItemPolicy policy = null, string regionName = null) { bool isUpDated = true; // Remove the item from the cache if it already exists. MemoryCache will // not add an item with an existing name. if (GetItem(key, regionName) != null) { isUpDated = RemoveItem(key, regionName); } if (policy == null) { // Create a new cache policy with the default values policy = new CacheItemPolicy(); } if (isUpDated) { isUpDated = AddItem(key, value, policy, regionName); } return isUpDated; } /// /// Removes an item matching the given key from the cache. /// /// /// A unique identifier for the cache entry. /// /// /// Optional. A named region in the cache to which the cache entry can be added, /// if regions are implemented. The default value for the optional parameter /// is null. /// /// /// True if the removal try succeeds, or false if there is an already an entry /// in the cache with the same key as key. /// public static bool RemoveItem(string key, string regionName = null) { bool isRemoved; lock (Cache) { isRemoved = Cache.Remove(key, regionName) != null; if (isRemoved) { string removedValue; CacheItems.TryRemove(key, out removedValue); } } return isRemoved; } /// /// Clears the cache. /// /// /// The region name. /// /// /// The . /// public static bool Clear(string regionName = null) { bool isCleared = false; lock (CacheItems) { // You can't remove items from a collection whilst you are iterating over it so you need to // create a collection to store the items to remove. ConcurrentDictionary tempDictionary = new ConcurrentDictionary(); foreach (KeyValuePair cacheItem in CacheItems) { // Does the cached key come with a region. if ((cacheItem.Value == null) || (cacheItem.Value != null && cacheItem.Value.Equals(regionName, StringComparison.OrdinalIgnoreCase))) { isCleared = RemoveItem(cacheItem.Key, cacheItem.Value); if (isCleared) { string key = cacheItem.Key; string value = cacheItem.Value; tempDictionary.AddOrUpdate(key, value, (oldkey, oldValue) => value); } } } if (isCleared) { // Loop through and clear out the dictionary of cache keys. foreach (KeyValuePair cacheItem in tempDictionary) { string removedValue; CacheItems.TryRemove(cacheItem.Key, out removedValue); } } } return isCleared; } } }