Sebagai permulaan izinkan saya membuangnya di sana bahwa saya tahu kode di bawah ini tidak aman untuk utas (koreksi: mungkin). Apa yang saya perjuangkan adalah menemukan implementasi yang benar-benar bisa gagal dalam pengujian. Saya refactoring proyek WCF besar sekarang yang membutuhkan beberapa (kebanyakan) data statis cache dan diisi dari database SQL. Itu harus kedaluwarsa dan "menyegarkan" setidaknya sekali sehari itulah sebabnya saya menggunakan MemoryCache.
Saya tahu bahwa kode di bawah ini seharusnya tidak thread safe tetapi saya tidak bisa membuatnya gagal di bawah beban berat dan untuk memperumit masalah, pencarian google menunjukkan implementasi kedua cara (dengan dan tanpa kunci dikombinasikan dengan perdebatan apakah perlu atau tidak.
Bisakah seseorang dengan pengetahuan MemoryCache dalam lingkungan multi-threaded memberi tahu saya secara pasti apakah saya perlu mengunci atau tidak di tempat yang sesuai sehingga panggilan untuk menghapus (yang jarang akan dipanggil tetapi persyaratannya) tidak akan muncul selama pengambilan / populasi kembali.
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<IPunctuationMapDto>().Any(p => 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 && table.Rows.Count != 0)
{
return AutoMapper.Mapper.DynamicMap<IDataReader, IEnumerable<PunctuationMapDto>>(table.CreateDataReader());
}
return null;
}
}