web-dev-qa-db-ja.com

Web APIでのデータのキャッシュ

ASP.NET Web API ODataサービスで利用可能な、ほとんど静的な(1日に1倍の変更がある可能性がある)オブジェクトのコレクションをキャッシュする必要があります。この結果セットはコール全体で使用されるため(クライアントコール固有ではありません)、アプリケーションレベルでキャッシュする必要があります。

私は「Web APIでのキャッシュ」を検索しましたが、結果はすべて「出力キャッシュ」に関するものでした。それは私がここで探しているものではありません。 「People」コレクションをキャッシュして、後続の呼び出しで再利用します(スライド式の有効期限があります)。

私の質問は、これはまだ単なるASP.NETであるため、このコレクションをメモリに永続化するために従来のアプリケーションキャッシング手法を使用するのか、それとも他に何かする必要があるのですか?このコレクションはnotユーザーに直接返されますが、API呼び出しを介したODataクエリの背後でソースとして使用されます。すべての呼び出しでexact同じ情報を取得するために、すべての呼び出しでデータベースにアクセスする理由はありません。 1時間ごとに期限切れで十分です。

このシナリオでデータを適切にキャッシュする方法を知っている人はいますか?

36
atconway

はい、出力キャッシュはあなたが探しているものではありません。 http://msdn.Microsoft.com/en-us/library/system.runtime.caching.memorycache.aspx のように、MemoryCacheを使用してメモリにデータをキャッシュできます。ただし、アプリケーションプールがリサイクルされると、そのデータは失われます。別のオプションは、AppFabric CacheやMemCacheなどの分散キャッシュを使用して、いくつかの名前を付けることです。

27
Pablo Cibraro

使用したソリューションは、System.Runtime.Caching名前空間のMemoryCacheに関係していました。コレクションをキャッシュするために機能するようになったコードは次のとおりです。

//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;

ロックと並行性を考慮するためにLazy<T>を使用して見つけた別の方法を次に示します。合計クレジットは、この投稿に行きます: 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