<p>I know in certain circumstances, such as long running processes, it is important to lock ASP.NET cache in order to avoid subsequent requests by another user for that resource from executing the long process again instead of hitting the cache.</p>

<p>What is the best way in c# to implement cache locking in ASP.NET?  </p>

[{'answer_id': 39144, 'author': 'khebbie', 'author_id': 4189, 'author_profile': 'https://Stackoverflow.com/users/4189', 'pm_score': 2, 'selected': False, 'text': '<p>Craig Shoemaker has made an excellent show on asp.net caching:\n<a href="http://polymorphicpodcast.com/shows/webperformance/" rel="nofollow noreferrer">http://polymorphicpodcast.com/shows/webperformance/</a></p>\n'}, {'answer_id': 39150, 'author': 'Jon Limjap', 'author_id': 372, 'author_profile': 'https://Stackoverflow.com/users/372', 'pm_score': 0, 'selected': False, 'text': '<p>This article from CodeGuru explains various cache locking scenarios as well as some best practices for ASP.NET cache locking:</p>\n\n<p><a href="http://www.codeguru.com/csharp/.net/net_asp/article.php/c5363/" rel="nofollow noreferrer">Synchronizing Cache Access in ASP.NET</a></p>\n'}, {'answer_id': 40065, 'author': 'a7drew', 'author_id': 4239, 'author_profile': 'https://Stackoverflow.com/users/4239', 'pm_score': 8, 'selected': True, 'text': "<p>Here's the basic pattern:</p>\n\n<ul>\n<li>Check the cache for the value, return if its available</li>\n<li>If the value is not in the cache, then implement a lock</li>\n<li>Inside the lock, check the cache again, you might have been blocked</li>\n<li>Perform the value look up and cache it</li>\n<li>Release the lock</li>\n</ul>\n\n<p>In code, it looks like this:</p>\n\n<pre><code>private static object ThisLock = new object();\n\npublic string GetFoo()\n{\n\n  // try to pull from cache here\n\n  lock (ThisLock)\n  {\n    // cache was empty before we got the lock, check again inside the lock\n\n    // cache is still empty, so retreive the value here\n\n    // store the value in the cache here\n  }\n\n  // return the cached value here\n\n}\n</code></pre>\n"}, {'answer_id': 40106, 'author': 'Seb Nilsson', 'author_id': 2429, 'author_profile': 'https://Stackoverflow.com/users/2429', 'pm_score': 1, 'selected': False, 'text': '<p>I saw one pattern recently called Correct State Bag Access Pattern, which seemed to touch on this.</p>\n\n<p>I modified it a bit to be thread-safe.</p>\n\n<p><a href="http://weblogs.asp.net/craigshoemaker/archive/2008/08/28/asp-net-caching-and-performance.aspx" rel="nofollow noreferrer">http://weblogs.asp.net/craigshoemaker/archive/2008/08/28/asp-net-caching-and-performance.aspx</a></p>\n\n<pre><code>private static object _listLock = new object();\n\npublic List List() {\n    string cacheKey = "customers";\n    List myList = Cache[cacheKey] as List;\n    if(myList == null) {\n        lock (_listLock) {\n            myList = Cache[cacheKey] as List;\n            if (myList == null) {\n                myList = DAL.ListCustomers();\n                Cache.Insert(cacheKey, mList, null, SiteConfig.CacheDuration, TimeSpan.Zero);\n            }\n        }\n    }\n    return myList;\n}\n</code></pre>\n'}, {'answer_id': 41314, 'author': 'John Owen', 'author_id': 2471, 'author_profile': 'https://Stackoverflow.com/users/2471', 'pm_score': 5, 'selected': False, 'text': '<p>For completeness a full example would look something like this.</p>\n\n<pre><code>private static object ThisLock = new object();\n...\nobject dataObject = Cache["globalData"];\nif( dataObject == null )\n{\n    lock( ThisLock )\n    {\n        dataObject = Cache["globalData"];\n\n        if( dataObject == null )\n        {\n            //Get Data from db\n             dataObject = GlobalObj.GetData();\n             Cache["globalData"] = dataObject;\n        }\n    }\n}\nreturn dataObject;\n</code></pre>\n'}, {'answer_id': 3135475, 'author': 'user378380', 'author_id': 378380, 'author_profile': 'https://Stackoverflow.com/users/378380', 'pm_score': 4, 'selected': False, 'text': '<p>Just to echo what Pavel said, I believe this is the most thread safe way of writing it</p>\n\n<pre><code>private T GetOrAddToCache&lt;T&gt;(string cacheKey, GenericObjectParamsDelegate&lt;T&gt; creator, params object[] creatorArgs) where T : class, new()\n    {\n        T returnValue = HttpContext.Current.Cache[cacheKey] as T;\n        if (returnValue == null)\n        {\n            lock (this)\n            {\n                returnValue = HttpContext.Current.Cache[cacheKey] as T;\n                if (returnValue == null)\n                {\n                    returnValue = creator(creatorArgs);\n                    if (returnValue == null)\n                    {\n                        throw new Exception("Attempt to cache a null reference");\n                    }\n                    HttpContext.Current.Cache.Add(\n                        cacheKey,\n                        returnValue,\n                        null,\n                        System.Web.Caching.Cache.NoAbsoluteExpiration,\n                        System.Web.Caching.Cache.NoSlidingExpiration,\n                        CacheItemPriority.Normal,\n                        null);\n                }\n            }\n        }\n\n        return returnValue;\n    }\n</code></pre>\n'}, {'answer_id': 23154648, 'author': 'nfplee', 'author_id': 155899, 'author_profile': 'https://Stackoverflow.com/users/155899', 'pm_score': 2, 'selected': False, 'text': "<p>I have come up with the following extension method:</p>\n\n<pre><code>private static readonly object _lock = new object();\n\npublic static TResult GetOrAdd&lt;TResult&gt;(this Cache cache, string key, Func&lt;TResult&gt; action, int duration = 300) {\n    TResult result;\n    var data = cache[key]; // Can't cast using as operator as TResult may be an int or bool\n\n    if (data == null) {\n        lock (_lock) {\n            data = cache[key];\n\n            if (data == null) {\n                result = action();\n\n                if (result == null)\n                    return result;\n\n                if (duration &gt; 0)\n                    cache.Insert(key, result, null, DateTime.UtcNow.AddSeconds(duration), TimeSpan.Zero);\n            } else\n                result = (TResult)data;\n        }\n    } else\n        result = (TResult)data;\n\n    return result;\n}\n</code></pre>\n\n<p>I have used both @John Owen and @user378380 answers. My solution allows you to store int and bool values within the cache aswell.</p>\n\n<p>Please correct me if there's any errors or whether it can be written a little better.</p>\n"}, {'answer_id': 24080538, 'author': 'Michael Logutov', 'author_id': 219900, 'author_profile': 'https://Stackoverflow.com/users/219900', 'pm_score': 0, 'selected': False, 'text': '<p>I\'ve wrote a library that solves that particular issue: <a href="https://github.com/MichaelLogutov/Rocks.Caching" rel="nofollow">Rocks.Caching</a></p>\n\n<p>Also I\'ve blogged about this problem in details and explained why it\'s important <a href="http://michaellogutov.com/caching-in-multi-thread-application-its-not-that-simple/" rel="nofollow">here</a>.</p>\n'}, {'answer_id': 26523173, 'author': 'Tarık Özgün Güner', 'author_id': 1786056, 'author_profile': 'https://Stackoverflow.com/users/1786056', 'pm_score': 0, 'selected': False, 'text': "<p>I modified @user378380's code for more flexibility. Instead of returning TResult now returns object for accepting different types in order. Also adding some parameters for flexibility. All the idea belongs to\n @user378380.</p>\n\n<pre><code> private static readonly object _lock = new object();\n\n\n//If getOnly is true, only get existing cache value, not updating it. If cache value is null then      set it first as running action method. So could return old value or action result value.\n//If getOnly is false, update the old value with action result. If cache value is null then      set it first as running action method. So always return action result value.\n//With oldValueReturned boolean we can cast returning object(if it is not null) appropriate type on main code.\n\n\n public static object GetOrAdd&lt;TResult&gt;(this Cache cache, string key, Func&lt;TResult&gt; action,\n    DateTime absoluteExpireTime, TimeSpan slidingExpireTime, bool getOnly, out bool oldValueReturned)\n{\n    object result;\n    var data = cache[key]; \n\n    if (data == null)\n    {\n        lock (_lock)\n        {\n            data = cache[key];\n\n            if (data == null)\n            {\n                oldValueReturned = false;\n                result = action();\n\n                if (result == null)\n                {                       \n                    return result;\n                }\n\n                cache.Insert(key, result, null, absoluteExpireTime, slidingExpireTime);\n            }\n            else\n            {\n                if (getOnly)\n                {\n                    oldValueReturned = true;\n                    result = data;\n                }\n                else\n                {\n                    oldValueReturned = false;\n                    result = action();\n                    if (result == null)\n                    {                            \n                        return result;\n                    }\n\n                    cache.Insert(key, result, null, absoluteExpireTime, slidingExpireTime);\n                }\n            }\n        }\n    }\n    else\n    {\n        if(getOnly)\n        {\n            oldValueReturned = true;\n            result = data;\n        }\n        else\n        {\n            oldValueReturned = false;\n            result = action();\n            if (result == null)\n            {\n                return result;\n            }\n\n            cache.Insert(key, result, null, absoluteExpireTime, slidingExpireTime);\n        }            \n    }\n\n    return result;\n}\n</code></pre>\n"}, {'answer_id': 38907980, 'author': 'cwills', 'author_id': 256475, 'author_profile': 'https://Stackoverflow.com/users/256475', 'pm_score': 5, 'selected': False, 'text': '<p>There is no need to lock the whole cache instance, rather we only need to lock the specific key that you are inserting for. \nI.e. No need to block access to the female toilet while you use the male toilet :)</p>\n\n<p>The implementation below allows for locking of specific cache-keys using a concurrent dictionary. This way you can run GetOrAdd() for two different keys at the same time - but not for the same key at the same time. </p>\n\n<pre><code>using System;\nusing System.Collections.Concurrent;\nusing System.Web.Caching;\n\npublic static class CacheExtensions\n{\n    private static ConcurrentDictionary&lt;string, object&gt; keyLocks = new ConcurrentDictionary&lt;string, object&gt;();\n\n    /// &lt;summary&gt;\n    /// Get or Add the item to the cache using the given key. Lazily executes the value factory only if/when needed\n    /// &lt;/summary&gt;\n    public static T GetOrAdd&lt;T&gt;(this Cache cache, string key, int durationInSeconds, Func&lt;T&gt; factory)\n        where T : class\n    {\n        // Try and get value from the cache\n        var value = cache.Get(key);\n        if (value == null)\n        {\n            // If not yet cached, lock the key value and add to cache\n            lock (keyLocks.GetOrAdd(key, new object()))\n            {\n                // Try and get from cache again in case it has been added in the meantime\n                value = cache.Get(key);\n                if (value == null &amp;&amp; (value = factory()) != null)\n                {\n                    // TODO: Some of these parameters could be added to method signature later if required\n                    cache.Insert(\n                        key: key,\n                        value: value,\n                        dependencies: null,\n                        absoluteExpiration: DateTime.Now.AddSeconds(durationInSeconds),\n                        slidingExpiration: Cache.NoSlidingExpiration,\n                        priority: CacheItemPriority.Default,\n                        onRemoveCallback: null);\n                }\n\n                // Remove temporary key lock\n                keyLocks.TryRemove(key, out object locker);\n            }\n        }\n\n        return value as T;\n    }\n}\n</code></pre>\n'}]
['https://Stackoverflow.com/questions/39112', 'https://Stackoverflow.com', 'https://Stackoverflow.com/users/2471/']