Das .NET-Framework enthält seit seinen ersten Tagen eine Cache-Implementierung allerdings lediglich für Web-Applikationen. Um auch andere Applikationen von Caching-Mechanismen profitieren zu lassen, werden entsprechende Konstrukte ab Version 4 für sämtliche Applikationen über den Namespace System.Runtime.Caching in der gleichnamigen Assembly angeboten. Die damit bereitgestellte Implementierung ähnelt jener von ASP.NET und sieht zurzeit lediglich einen In-Memory-Cache (MemoryCache) vor. Weitere Cache-Implementierungen können jedoch durch Ableiten von der Basisklasse ObjectCache entwickelt werden.

Dieser Blogeintrag ist ein Auszug aus meinem aktuellen Buch .Net 4 Update.
Ein Beispiel für die Verwendung von MemoryCache findet sich im nachfolgenden Listing. Zunächst wird hier über die statische Eigenschaft MemoryCache.Default eine Referenz auf die global bereitgestellte Standard-Instanz von MemoryCache bezogen und versucht, über den Schlüssel someText einen gecachten String abzurufen. Konnte dieser nicht ermittelt werden, wird der Eintrag aus einer Datei gelesen sowie unter dem mit ihm assoziierten Schlüssel someText im Cache abgelegt. Im Zuge dessen wird auch eine CacheItemPolicy übergeben. Diese legt fest, wann der Cache-Eintrag wieder aus dem Cache entfernt werden soll. Dazu wird mit der Eigenschaft SlidingExpiration festgelegt, nach welchem Zeitraum, in welchem nicht auf das Element zugegriffen wird, dieses zu entfernen ist. Alternativ dazu kann mit der Eigenschaft AbsoluteExpiration eine absolute Zeitspanne, nach welcher der Eintrag entfernt werden soll, angeführt werden. Daneben bietet Priority vom Enum-Typ CacheItemPriority die Möglichkeit zu definieren, dass ein Eintrag gar nicht aus dem Cache entfernt werden soll. Dies wird mit dem Wert NotRemovable angezeigt. Zusätzlich zur SlidingExpiration wird auch ein ChangeMonitor vom Typ HostFileChangeMonitor registriert. Dieser überwacht die an den Konstruktor übergebenen Dateien und/oder Ordner auf Änderungen. Im Fall einer Änderung werden die mit der Policy assoziierten Einträge aus dem Cache entfernt. Neben dem HostFileChangeMonitor existiert auch ein SqlChangeMonitor, welcher eine Instanz der seit .NET 2.0 verfügbaren Klasse SqlDependency kapselt und diese zur Überwachung von Änderungen in einer SQL Server-Datenbank (ab Version 2005) verwendet. Weitere derartige Mechanismen können durch Ableiten von der Basisklasse ChangeMonitor oder einer deren Subklassen bereitgestellt werden.
const string source = @c:\temp\someTextFile.txt;
ObjectCache cache = MemoryCache.Default;
string fileContents = cache[someText] as string;
if (fileContents == null)
{
Console.WriteLine(Element war nicht (mehr) im Cache!);
CacheItemPolicy policy = new CacheItemPolicy();
policy.SlidingExpiration = TimeSpan.FromSeconds(50);
List<string> filePaths = new List<string>();
filePaths.Add(source);
policy.ChangeMonitors.Add(new HostFileChangeMonitor(filePaths));
fileContents = File.ReadAllText(source);
cache.Set(someText, fileContents, policy);
}
Console.WriteLine(fileContents);
Um die verwendeten Caches über die Applikationskonfigurationsdatei anpassen zu können, kann jeder Instanz von MemoryCache ein Name spendiert werden. Der Name der im letzten Listing verwendeten Standard-Instanz lautet auf Default. Weiteren Instanzen kann, nachfolgend gezeigt, über den Konstruktor ein Name zugewiesen werden. Dabei gilt zu beachten, dass es verschiedene Instanzen mit demselben Namen geben kann.
In der Applikationskonfigurationsdatei können diesen Namen Konfigurationseigenschaften zugewiesen werden. Im nachfolgenden Listing wird beispielsweise für den Cache mit dem Namen MyCache festgelegt, dass dieser max. 10 MB einnehmen soll (cacheMemoryLimitMegabytes) bzw. max. 15 % des physikalischen Speichers (physicalMemoryLimitPercentage) sowie dass in Intervallen von einer Minute (pollingInterval) geprüft werden soll, ob diese Grenzen überschritten wurden. Als Alternative zur Definition dieser Parameter über die Applikationskonfiguration besteht auch die Möglichkeit diese in Form einer NameValueCollection an den Konstruktor von MemoryCache zu Übergeben.
private static MemoryCache cache;
private static void CacheDemo2()
{
const string source = @c:\temp\someTextFile.txt;
if (cache == null) cache = new MemoryCache(MyCache);
string fileContents = cache[someText] as string;
if (fileContents == null)
{
Console.WriteLine(Element war nicht (mehr) im Cache!);
CacheItemPolicy policy = new CacheItemPolicy();
List<string> filePaths = new List<string>();
filePaths.Add(source);
policy.ChangeMonitors.Add(new HostFileChangeMonitor(filePaths));
policy.SlidingExpiration = TimeSpan.FromSeconds(50);
fileContents = File.ReadAllText(source);
cache.Set(someText, fileContents, policy);
}
Console.WriteLine(fileContents);
}
<system.runtime.caching>
<memoryCache>
<namedCaches>
<add name=MyCache
cacheMemoryLimitMegabytes=10
physicalMemoryLimitPercentage=15
pollingInterval=00:01:00 />
</namedCaches>
</memoryCache>
</system.runtime.caching>