Enterprise Library 4 March 2008 CTP – Caching-Wrapper
Bevor man die Enterprise Library 4 March 2008 CTP herunterlädt, sollte man wissen, dass es einige Probleme mit sich bringt, diese auf einem Windows XP System zu übersetzen. Grund dafür ist, dass die derzeitge Version noch eine Abhängigkeit zu dem Auhtorization-Manager enthält, welcher auf einem Windows XP System nicht zur Verfügung steht. Eine Hilfe, wie man diesen Part nachinstallieren kann, findet man im Diskussions-Forum in Form einer Antwort von Paul Taylor.
Hat man die Enterprise Library 4 March 2008 CTP nun erfolgreich übersetzt, kann man sich überlegen, diese in den GAC zu installieren oder lokal über Probing aufzulösen. Ich entscheide mich gerne für letztere Möglichekit, da diese das einfache XCopy oder andere Formen des Deployments ermöglicht.
Nachdem alle Vorbereitungen getroffen sind, findet man bei Microsoft einen Überblick über den Caching Application Block. Zwar noch aus der älteren Enterprise Library 3.1, aber an den grundlegenden Konzepten hat sich nicht allzu viel verändert. Wie man dem ChangeLog entnehmen kann:
The application block has been refactored to allow developers to replace the CacheManagerclass with their own implementation if required. This does not affect the API of the application block or the existing CacheManager. Developers can install and configure a custom cache manager implementation using the configuration tools provided that the new class implements the ICacheManagerinterface and carries the following attribute.
The application block implements several new performance counters that you can use to monitor performance and operations. The new counters are Total Cache Hits, Total Cache Misses, Total Cache Expiries, Total Cache Scavenged Items, and Total Updated Entries.
Sind die Grundlagen klar, können wir uns unserem eigentlich Problem widmen. Was ist zu erreichen? Stellen wir uns vor, wir haben eine klassische NTier Architektur. Es gibt Strukturen, wie DataSet’s oder DataTable’s, welche zur Laufzeit ausgewertet werden, um Eingabemasken zu generieren und diese in Form von Assemblies dynamisch zu erzeugen. Diese Strukturen ändern sich nicht in solchem Maße, so dass diese hervorragend am Client gecached werden könnten und nur bei Bedarf aktualisiert. Daraus ergibt sich aber auch die Anforderung, dass dieser Cache ein Beenden und Neustarten des Clients überdauern kann. Zusätzlich sollen die gepseicherten Objekte transparent, sprich sind diese nicht im Cache enthalten, nachgeladen werden, Typsicherheit wäre schön, um eine boxing und unboxing überflüssig zu machen. Events, die bei Veränderung des Caches gefeuert würden, könnten von Hilfe sein und wenn der Cache die neuen LINQ-Mechanismen unterstützen würde, wäre das Rundum-Sorglos-Paket fertig.
Out of the Box unterstützt die Enterprise Library 4 March 2008 CTP nicht alle dieser Anforderungen, da aber auch eine andere Intention im Vordergrund steht. Klar sollte sein, dass die Implementierung einer Typsicherheit nach sich zieht, dass jeder unterschiedliche Objekttyp einen neuen Cache mit sich bringt, es sei denn man würde einen typsicheren Objekt-Chache implementieren, welcher aber wiederum boxing und unboxing mit sich bringen würde. Ein weiteres Manko ist, dass der Cache des Application-Blocks keinen direkten Zugriff auf die Schlüssel und Werte des Caches zulässt, aber auch das kann per Reflection umgangen werden.
Die daraus entstandene Klasse kann am Ende des Artikels oder im Download-Bereich heruntergeladen werden. Die wichtigsten Code-Segmente mit einigen Erläuterungen folgen jetzt.
Zugriff auf den internen Cache per Reflection:
private Cache GetRealCache()
{
return (Cache)this.InternalCache.GetType().GetField("realCache", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(this.InternalCache);
}
Dieser reale Cache ermöglicht die Unterstützung der LINQ-Mechanismen, auf die Schlüssel:
public IEnumerable<String> Keys
{
get
{
return this.RealCache.CurrentCacheState.Keys.Cast<String>();
}
}
Und auf die Werte:
public IEnumerable<TType> Values
{
get
{
return this.RealCache.CurrentCacheState.Values.Cast<TType>();
}
}
Der aufmerksame Leser hat sicher den Type TType bemerkt, welcher uns per Generics die Typsicherheit beschert:
public sealed class Cache<TType>
Die Konstruktor-Signatur
public Cache(String qualifier, ICacheLoader<TType> loader)
zeigt, dass neben der Konfigurationskennzeichnung (qualifier) ein ICacheLoader<TType> übergeben werden kann. Dieser ermöglicht das typsichere Nachladen der Objekte, falls diese aus dem Cache abgerufen, aber nicht enthalten sind.
Das ganze um ein paar Events und einen Indexer erweitert, liefert das vollständige Resultat. Um den Cache in einem Projekt verwenden zu können, muss dieser per App.config konfiguriert werden.
<configuration>
<configSections>
<section name="cachingConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Caching.Configuration.CacheManagerSettings, Microsoft.Practices.EnterpriseLibrary.Caching, Version=3.1.0.0, Culture=neutral, PublicKeyToken=null" requirePermission="false" />
</configSections>
<cachingConfiguration defaultCacheManager="MyCache">
<cacheManagers>
<add expirationPollFrequencyInSeconds="60" maximumElementsInCacheBeforeScavenging="1000"
numberToRemoveWhenScavenging="10" backingStoreName="Isolated-Cache-Storage"
type="Microsoft.Practices.EnterpriseLibrary.Caching.CacheManager, Microsoft.Practices.EnterpriseLibrary.Caching, Version=3.1.0.0, Culture=neutral, PublicKeyToken=null"
name="MyCache" />
</cacheManagers>
<backingStores>
<add partitionName="MyCache" encryptionProviderName="" type="Microsoft.Practices.EnterpriseLibrary.Caching.BackingStoreImplementations.IsolatedStorageBackingStore, Microsoft.Practices.EnterpriseLibrary.Caching, Version=3.1.0.0, Culture=neutral, PublicKeyToken=null" name="Isolated-Cache-Storage" />
</backingStores>
</cachingConfiguration>
</configuration>
Diese Konfiguration kann man allerdings lieber mit dem mitgelieferten Konfigurations-Tool EntLibConfig.exe erledigen als von Hand.
Ein simpler Testfall, der die LINQ-Mechanismen testet könnte wie folgt aussehen:
Cache<String> cache = new Cache<String>("MyCache", null);
cache.Add("Key", "Value");
cache.Add("Key1", "Value1");
cache.Add("Key2", "Value2");
cache.Add("Key12", "Value12");
cache.Add("Key13", "Value13");
var keys = from key in cache.Keys where key.StartsWith("Key1") select key;
Assert.IsTrue(keys.Count() == 3);
Die gesamte Projektmappe (Visual Studio 2008 Projekt) kann hier heruntergeladen werden:
Enterprise Library 4.0 (Caching-Wrapper) (171.7 KiB, 418 hits)