Pour commencer, laissez-moi simplement dire que je sais que le code ci-dessous n'est pas thread-safe (correction: peut-être). Ce avec quoi j'ai du mal, c'est de trouver une implémentation qui soit et que je puisse réellement réussir à échouer lors des tests. Je suis en train de refactoriser un grand projet WCF qui nécessite des données (principalement) statiques mises en cache et alimentées à partir d'une base de données SQL. Il doit expirer et "se rafraîchir" au moins une fois par jour, c'est pourquoi j'utilise MemoryCache.
Je sais que le code ci-dessous ne doit pas être thread-safe, mais je ne peux pas le faire échouer sous une charge lourde et pour compliquer les choses, une recherche Google montre les implémentations dans les deux sens (avec et sans verrous combinés à des débats sur la nécessité ou non de les utiliser.
Une personne connaissant MemoryCache dans un environnement multi-thread pourrait-elle me faire savoir définitivement si je dois ou non verrouiller le cas échéant afin qu'un appel à supprimer (qui sera rarement appelé mais c'est une exigence) ne sera pas lancé lors de la récupération / repeuplement.
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;
}
}