title: MemoryCache Thread Safety, Is Locking Necessary?
body: <p>For starters let me just throw it out there that I know the code below is not thread safe (correction: might be). What I am struggling with is finding an implementation that is and one that I can actually get to fail under test. I am refactoring a large WCF project right now that needs some (mostly) static data cached and its populated from a SQL database. It needs to expire and "refresh" at least once a day which is why I am using MemoryCache.</p>
  
  <p>I know that the code below should not be thread safe but I cannot get it to fail under heavy load and to complicate matters a google search shows implementations both ways (with and without locks combined with debates whether or not they are necessary.</p>
  
  <p>Could someone with knowledge of MemoryCache in a multi threaded environment let me definitively know whether or not I need to lock where appropriate so that a call to remove (which will seldom be called but its a requirement) will not throw during retrieval/repopulation.</p>
  
  <pre><code>public class MemoryCacheService : IMemoryCacheService
  {
      private const string PunctuationMapCacheKey = "punctuationMaps";
      private static readonly ObjectCache Cache;
      private readonly IAdoNet _adoNet;
  
      static MemoryCacheService()
      {
          Cache = MemoryCache.Default;
      }
  
      public MemoryCacheService(IAdoNet adoNet)
      {
          _adoNet = adoNet;
      }
  
      public void ClearPunctuationMaps()
      {
          Cache.Remove(PunctuationMapCacheKey);
      }
  
      public IEnumerable GetPunctuationMaps()
      {
          if (Cache.Contains(PunctuationMapCacheKey))
          {
              return (IEnumerable) Cache.Get(PunctuationMapCacheKey);
          }
  
          var punctuationMaps = GetPunctuationMappings();
  
          if (punctuationMaps == null)
          {
              throw new ApplicationException("Unable to retrieve punctuation mappings from the database.");
          }
  
          if (punctuationMaps.Cast&lt;IPunctuationMapDto&gt;().Any(p =&gt; p.UntaggedValue == null || p.TaggedValue == null))
          {
              throw new ApplicationException("Null values detected in Untagged or Tagged punctuation mappings.");
          }
  
          // Store data in the cache
          var cacheItemPolicy = new CacheItemPolicy
          {
              AbsoluteExpiration = DateTime.Now.AddDays(1.0)
          };
  
          Cache.AddOrGetExisting(PunctuationMapCacheKey, punctuationMaps, cacheItemPolicy);
  
          return punctuationMaps;
      }
  
      //Go oldschool ADO.NET to break the dependency on the entity framework and need to inject the database handler to populate cache
      private IEnumerable GetPunctuationMappings()
      {
          var table = _adoNet.ExecuteSelectCommand("SELECT [id], [TaggedValue],[UntaggedValue] FROM [dbo].[PunctuationMapper]", CommandType.Text);
          if (table != null &amp;&amp; table.Rows.Count != 0)
          {
              return AutoMapper.Mapper.DynamicMap&lt;IDataReader, IEnumerable&lt;PunctuationMapDto&gt;&gt;(table.CreateDataReader());
          }
  
          return null;
      }
  }
  </code></pre>