web-dev-qa-db-fra.com

Mise en cache des données dans l'API Web

J'ai besoin de mettre en cache une collection d'objets principalement statiques (pouvant avoir des modifications 1x par jour) disponibles dans mon service OData de l'API Web ASP.NET. Cet ensemble de résultats est utilisé pour tous les appels (ce qui signifie qu'il n'est pas spécifique à l'appel client), il doit donc être mis en cache au niveau de l'application.

J'ai fait beaucoup de recherches sur la "mise en cache dans l'API Web", mais tous les résultats concernaient la "mise en cache de sortie". Ce n'est pas ce que je recherche ici. Je souhaite mettre en cache une collection "People" à réutiliser lors d'appels ultérieurs (peut avoir une expiration glissante).

Ma question est, puisque ce n'est encore qu'ASP.NET, est-ce que j'utilise des techniques traditionnelles de mise en cache d'application pour conserver cette collection en mémoire, ou y a-t-il autre chose que je dois faire? Cette collection est pas directement retournée à l'utilisateur, mais plutôt utilisée comme source en arrière-plan pour les requêtes OData via des appels d'API. Il n'y a aucune raison pour moi d'aller à la base de données à chaque appel pour obtenir les exactes mêmes informations à chaque appel. Son expiration toutes les heures devrait suffire.

Quelqu'un sait comment mettre correctement en cache les données dans ce scénario?

36
atconway

Oui, la mise en cache de sortie n'est pas ce que vous recherchez. Vous pouvez mettre en cache les données en mémoire avec MemoryCache par exemple, http://msdn.Microsoft.com/en-us/library/system.runtime.caching.memorycache.aspx . Cependant, vous perdrez ces données si le pool d'applications est recyclé. Une autre option consiste à utiliser un cache distribué comme AppFabric Cache ou MemCache pour n'en nommer que quelques-uns.

27
Pablo Cibraro

La solution que j'ai fini par utiliser impliquée MemoryCache dans le System.Runtime.Caching espace de noms. Voici le code qui a fini par fonctionner pour mettre en cache ma collection:

//If the data exists in cache, pull it from there, otherwise make a call to database to get the data
ObjectCache cache = MemoryCache.Default;

var peopleData = cache.Get("PeopleData") as List<People>;
if (peopleData != null)
   return peopleData ;

peopleData = GetAllPeople();
CacheItemPolicy policy = new CacheItemPolicy {AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(30)};
cache.Add("PeopleData", peopleData, policy);
return peopleData;

Voici une autre façon que j'ai trouvée en utilisant Lazy<T> pour prendre en compte le verrouillage et la simultanéité. Le crédit total va à ce poste: Comment gérer les opérations de construction coûteuses en utilisant MemoryCache?

private IEnumerable<TEntity> GetFromCache<TEntity>(string key, Func<IEnumerable<TEntity>> valueFactory) where TEntity : class 
{
    ObjectCache cache = MemoryCache.Default;
    var newValue = new Lazy<IEnumerable<TEntity>>(valueFactory);            
    CacheItemPolicy policy = new CacheItemPolicy { AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(30) };
    //The line below returns existing item or adds the new value if it doesn't exist
    var value = cache.AddOrGetExisting(key, newValue, policy) as Lazy<IEnumerable<TEntity>>;
    return (value ?? newValue).Value; // Lazy<T> handles the locking itself
}
42
atconway