2013-05-08 1 views
29

Ich habe die Notwendigkeit, eine Sammlung von Objekten, die größtenteils statisch ist (möglicherweise 1x pro Tag Änderungen), die in meinem OData-Dienst ASP.NET Web API verfügbar ist. Diese Ergebnismenge wird für alle Anrufe verwendet (dh nicht für den Client-Anruf). Daher muss sie auf Anwendungsebene zwischengespeichert werden.Zwischenspeichern von Daten in Web-API

Ich habe eine Reihe von Suchen über "Caching in Web-API" durchgeführt, aber alle Ergebnisse waren über "Ausgabe-Caching". Das ist nicht das, wonach ich hier suche. Ich möchte eine 'People'-Sammlung zwischenspeichern, die bei nachfolgenden Aufrufen wiederverwendet werden kann (möglicherweise mit gleitendem Ablaufdatum).

Meine Frage ist, da dies immer noch nur ASP.NET ist, verwende ich traditionelle Anwendung Caching-Techniken für die Persistenz dieser Sammlung im Speicher, oder gibt es noch etwas, was ich tun muss? Diese Sammlung wird nicht direkt an den Benutzer zurückgegeben, sondern eher als Quelle hinter den Kulissen für OData-Abfragen über API-Aufrufe verwendet. Es gibt keinen Grund für mich, in die Datenbank bei jedem Anruf die genaue gleiche Informationen bei jedem Anruf zu gehen. Es stündlich auslaufen sollte ausreichen.

Kann jemand die Daten in diesem Szenario richtig zwischenspeichern?

Antwort

21

Ja, Ausgabe-Caching ist nicht das, was Sie suchen. Sie können die Daten im Speicher mit MemoryCache speichern, z. B. http://msdn.microsoft.com/en-us/library/system.runtime.caching.memorycache.aspx. Sie verlieren diese Daten jedoch, wenn der Anwendungspool wiederverwendet wird. Eine andere Option ist die Verwendung eines verteilten Caches wie AppFabric Cache oder MemCache, um nur einige zu nennen.

+0

Ja nach diesem Schreiben fand ich 'MemoryCache' im' System.Runtime.Caching' Namespace, der perfekt aussieht. Der Vorbehalt, dass ich die Daten verlieren könnte, wenn AppPool recycelt, ist OK, weil ich nur versuche zu verhindern, dass die DB bei jedem * API-Aufruf erneut aufgerufen wird. Die Verwendung von 'MemoryCache.Get()' und 'MemoryCache.Add()' scheint gut für mich zu funktionieren. 'AddOrGetExisting()' sah cool aus aber funktionierte nicht für meine Situation; es würde immer noch erforderlich sein, zuerst Daten von der DB zu holen, bevor sie anruft. Ich habe eine 'AbsoluteExpiration' von 30 Minuten eingestellt. – atconway

+5

Nur als eine Markierung, um Leuten auf dem Weg zu helfen, ist die empfohlene Caching-Technologie in Azure nun Redis. Redis oder ein anderer verteilter Cache ist erforderlich, wenn Sie mehr als eine Instanz Ihrer API haben. Azure Managed Cache ist jetzt sehr versteckt und nur von Powershell aus zugänglich. Sie halten es nur dort, um Leuten zu helfen, die es vorher benutzt haben. –

+0

Redis ist zu teuer, wenn Sie nur einige WebApi-Datenaufrufe zwischenspeichern. –

31

Die Lösung, die ich am Ende verwendete, beinhaltete MemoryCache im System.Runtime.Caching Namensraum. Hier ist der Code, der für das Caching von meiner Sammlung endete arbeiten:

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

Hier ist eine andere Art, wie ich mit Lazy<T> gefunden Rechnung Schließ- und Gleichzeitigkeit zu nehmen. Insgesamt Kredit geht zu diesem Beitrag: How to deal with costly building operations using 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 
} 
+1

wie diese GetFromCache-Methode zu nennen ist Was muss ich in ValueFactory-Parameter paas Wenn ich die Ausgabe von Get, die Aufrufe Repository speichert, wie man es verwenden und dann in nachfolgenden Aufruf verwenden? – F11