15.5 Den Cache automatisch aktualisieren
 
15.5.1 Den Cache vom Inhalt einer XML-Datei abhängig machen
 
Bei der Arbeit mit einem Cache muss man immer wieder raten und schätzen, wie lange eine Information sinnvollerweise im Cache gehalten werden sollte, bevor man sie vielleicht doch lieber neu erstellt. Wenn Sie beispielsweise auf der Website News darstellen und diese Seite stets für fünf Minuten im Cache bleibt, dann wird eine neue Meldung manchmal erst fünf Minuten nach der Aktualisierung auf den Browsern der Anwender erscheinen. Wenn Sie aber stets so aktuell wie möglich sein möchten, gibt es die Möglichkeit, den Cache punktgenau immer dann zu aktualisieren, wenn sich die zugrunde liegenden Daten ändern.
cache_09.aspx und cache_09.xml demonstrieren, wie der Inhalt des Caches an den Inhalt einer XML-Datei gekoppelt wird. Sobald die Datei geändert wird, wird automatisch auch der Cache aktualisiert. Abbildung 15.7 zeigt die Darstellung im Browser.
<!-- cache_09.aspx -->
<%@ Page Language="VB" Debug="True" Strict="True"
EnableViewState="false" %>
<%@ Import namespace="System.Data" %>
<%@ Import namespace="System.Xml" %>
<script runat="server">
Dim t As String
Sub Page_Load (ByVal Sender As Object, _
ByVal E As EventArgs)
Dim cacheKey As String = "News"
Dim myDS As DataSet
myDS = CType(Cache(cacheKey), DataSet)
If myDS Is Nothing Then
Dim xmlDatNam As String = "cache_09.xml"
' Daten aus der XML-Datei einlesen
myDs = New DataSet()
Dim xdoc As New XmlDataDocument()
xdoc.DataSet.ReadXml(Server.MapPath(xmlDatNam))
myDS = xdoc.DataSet
' Daten im Cache ablegen
Dim dep As New CacheDependency _
(Server.MapPath(xmlDatNam))
Cache.Insert (cacheKey, myDS, dep)
ausgabe.innerText = "Quelle: Neu geladen"
Else
ausgabe.innerText = "Quelle: Cache"
End If
dg.DataSource = myDS.Tables(2)
dg.DataBind()
End Sub
</script>
<html>
<head><title>Ein Cache-Objekt vom Inhalt einer
XML-Datei abhängig machen</title></head>
<body>
<h3>Ein Cache-Objekt vom Inhalt einer
XML-Datei abhängig machen</h3>
<form runat="server" >
<h3>Aktuelle News</h3>
<asp:DataGrid runat="server"
id="dg" >
</asp:DataGrid>
<p id="ausgabe" runat="server" />
</form></body></html>
 Hier klicken, um das Bild zu Vergrößern
Abbildung 15.7 Bei jeder Änderung in der XML-Datei wird der Cache automatisch aktualisiert.
<xml version="1.0" encoding='utf-8' >
<news>
<message>
<Datum>15.12.2002</Datum>
<Titel>Preis für Monitor "Gucki" halbiert.</Titel>
</message>
<message>
<Datum>14.12.2002</Datum>
<Titel>Teetasse "Hubert" jetzt viel billiger</Titel>
</message>
<message>
<Datum>13.12.2002</Datum>
<Titel>Das Sofa "Urmel" jetzt auch in Rot erhältlich.</Titel>
</message>
</news>
</xml>
Die Seite cache_09.aspx stellt die News in einer Tabelle dar. Diese Tabelle wird über ein serverseitiges DataGrid-Steuerelement erzeugt. Beim Laden der Seite cache_09.aspx wird ein DataSet-Objekt an dieses Steuerelement gebunden. Dieses DataSet-Objekt wird im Cache gehalten. In Page_Load ist außerdem der Fall vorgesehen, dass es noch kein entsprechendes Cache-Objekt gibt. In diesem Fall werden die Daten aus der XML-Datei eingelesen und neu im Cache abgelegt.
Beim Ablegen des DataSet-Objekts im Cache wird eine Cache-Abhängigkeit definiert.
Dim dep As New CacheDependency _
(Server.MapPath(xmlDatNam))
Server.MapPath erstellt den physischen Dateipfad zu dem übergebenen (virtuellen) Dateinamen. Diesen physischen Dateipfad benötigen Sie für den Konstruktor der CacheDependency-Klasse. Das bedeutet: Ein Cache-Element soll von dieser Datei abhängig sein. Sobald diese Datei sich ändert, soll das entsprechende Cache-Element aus dem Cache entfernt werden. Mit der nächsten Zeile wird das DataSet-Objekt mit dem in cacheKey enthaltenen Schlüssel und der in dep definierten Cache-Abhängigkeit in den Cache eingefügt.
Cache.Insert (cacheKey, myDS, dep)
Sobald die XML-Datei sich ändert, wird sie aus dem Cache entfernt. Der Cache wird aber nicht automatisch aktualisiert. Das müssen Sie selbst erledigen, und genau das macht die Page_Load-Prozedur.
Die Bindung an das DataGrid-Steuerelement erfolgt mit dieser Zeile:
dg.DataSource = myDS.Tables(2)
Das DataSet-Objekt enthält mehrere Tabellen. Die beiden ersten Tabellen enthalten strukturelle Informationen über den XML-Datenbestand. Erst die dritte Tabelle mit der Ordnungszahl 2 enthält die eigentlichen Datensätze. Eine Spalte news_Id wurde automatisch ergänzt und soll hier nicht weiter stören.
15.5.2 Weitere Möglichkeiten, den Cache abhängig zu machen
 
cache_09.aspx hat demonstriert, wie ein Cache-Objekt vom Inhalt einer XML-Datei abhängig gemacht werden kann. Es gibt weitere Möglichkeiten, den Cache vom Status anderer Elemente abhängig zu machen.
| Tipp Diese Möglichkeiten erschließen sich alle über die diversen Konstruktoren der CacheDependency-Klasse. Hier einige Beispiele:
|
Public Sub New(String())
Sie können den Cache von mehreren Dateien oder Verzeichnissen abhängig machen, indem Sie die entsprechenden Pfade in einem Array übergeben.
Public Sub New(String, DateTime)
Mit diesem Konstruktor übergeben Sie zusätzlich zu einem Dateipfad eine Zeitangabe. Die Überwachung startet zum genannten Zeitpunkt.
Der folgende Konstruktor bietet die Möglichkeit, einen Cache von mehreren Dateipfaden und von mehreren anderen Cache-Elementen abhängig zu machen. Im ersten Array werden die Dateiabhängigkeiten übergeben, das zweite Array führt die abhängigen Cache-Elemente auf:
Public Sub New(String(), String())
15.5.3 Den Cache über Prioritäten steuern
 
Wenn Sie mit der Add- oder Insert-Methode ein Objekt im Cache ablegen, können Sie zusätzlich einen Wert für die Priorität angeben. Wenn es im Arbeitsspeicher des Webservers eng wird, dann werden zunächst die Objekte mit niedrigerer Cache-Priorität aus dem Arbeitsspeicher entfernt. Tabelle 15.3 nennt die gültigen Abstufungen, die in der Enumeration CacheItemPriority enthalten sind.
| Wert
|
Bedeutung
|
| NotRemovable
|
Das Objekt wird gar nicht gelöscht.
|
| High
|
Das Objekt wird nur in Extremfällen gelöscht.
|
| AboveNormal
|
Höher als Normal, geringer als High
|
| Default
|
Default und Normal bedeuten die gleiche Stufe.
|
| Normal
|
Default und Normal bedeuten die gleiche Stufe.
|
| BelowNormal
|
Höher als Low, niedriger als Normal
|
| Low
|
Objekte mit dem Wert Low werden als Erste aus dem Speicher gelöscht.
|
Tabelle 15.3 Die Werte der Enumeration CacheItemPriority in absteigender Priorität geordnet
Der folgende Befehl fügt das Objekt myDS mit der Priorität High in den Cache ein.
Cache.Insert (cacheKey, _
myDS, _
dep, _
DateTime.MaxValue, _
TimeSpan.Zero, _
CacheItemPriority.High, _
Nothing)
Der letzte Parameter bezeichnet einen Wert für den Callback Support. Das ist das Thema des nächsten Abschnitts.
15.5.4 Reagieren, wenn ein Eintrag aus dem Cache gelöscht wird
 
ASP.NET bietet die Möglichkeit zu reagieren, wenn ein Eintrag aus dem Cache gelöscht wird. Dafür stellt ASP.NET den CacheItemRemovedCallback-Delegaten zur Verfügung. Eine entsprechende Funktionalität implementieren Sie in vier Schritten:
|
Sie definieren eine lokale Variable vom Typ CacheItemRemovedCallback. |
|
Sie definieren eine entsprechende Ereignisprozedur. |
|
Sie weisen der lokalen Variablen die Adresse der Ereignisprozedur zu. |
|
Wenn Sie das Objekt in den Cache einfügen, geben Sie zusätzlich diese Variable an. |
Zur Demonstration dieses Verfahrens kann cache_07.aspx ganz gut abgewandelt werden. cache_10.aspx zeigt, wie bei jeder Entfernung aus dem Cache eine Logdatei aktualisiert wird. Hier folgt zunächst der komplette Quellcode, an den sich die Erläuterungen anschließen. Abbildung 15.8 zeigt parallel zum Browser den Editor mit der automatisch erstellten Logdatei.
<!-- cache_10.aspx -->
<%@ Page Language="VB" Debug="True" Strict="True" %>
<script runat="server">
Private Shared onRemove _
As CacheItemRemovedCallback = Nothing
Sub btnOK_Click _
(Sender As Object, E As System.EventArgs)
onRemove = new CacheItemRemovedCallback _
(AddressOf Me.RemovedFromCache)
Cache.Insert("Topmeldung", _
TopText.value, _
Nothing, _
DateTime.Now.AddSeconds(10), _
TimeSpan.Zero, _
CacheItemPriority.Default, _
onRemove )
ausgabe.innerText = TopText.value
End Sub
Sub btnDelete_Click _
(Sender As Object, E As System.EventArgs)
Cache.Remove("Topmeldung")
ausgabe.innerText = ""
TopText.value=""
End Sub
Public Sub RemovedFromCache _
(key As String, _
value As Object, _
reason As CacheItemRemovedReason )
Dim w As System.IO.StreamWriter
w = new System.IO.StreamWriter _
("c:\\cachelog.txt", true)
w.WriteLine(DateTime.Now.ToString() _
& " " _
& key _
& ": " _
& value.ToString() _
& " – " _
& reason.ToString())
w.Close()
End Sub
</script>
<html><head><title>
Auf das Ereignis reagieren, dass ein Eintrag aus dem
Cache entfernt wird</title></head>
<body>
<h3>Auf das Ereignis reagieren, dass ein Eintrag aus
dem Cache entfernt wird</h3>
<form runat="server" >
Topmeldung<br>
<p>Aktuell gespeichert:
<span id="ausgabe" runat="server" /></p>
<input type="text" id="TopText" runat="server"
size="60">
<br>
<asp:Button runat="server" id="btnOK"
OnClick="btnOK_Click"
Text="Meldung speichern" />
<br><br>
<asp:Button runat="server" id="btnDelete"
OnClick="btnDelete_Click"
Text="Meldung löschen" />
</form>
<p>
<a href="c:\cachelog.txt">Cache-Log ansehen</a>
</p></body></html>
 Hier klicken, um das Bild zu Vergrößern
Abbildung 15.8 Mit einem Delegaten reagieren Sie auf das Entfernen eines Eintrags aus dem Cache.
Die Ereignisprozedur definieren
Zunächst benötigen Sie eine Prozedur, die beim Eintreten des Ereignisses Eintrag wird aus dem Cache gelöscht ausgeführt werden soll. Dieser Ereignisprozedur werden drei Werte übergeben:
|
der Schlüssel des Cache-Eintrags, |
|
das gecachte Objekt selbst und |
|
eine Angabe zum Grund, warum der Eintrag aus dem Cache entfernt wird. |
Damit ergibt sich diese Signatur:
Public Sub RemovedFromCache _
(key As String, _
value As Object, _
reason As CacheItemRemovedReason )
CacheItemRemovedReason ist eine Enumeration, die vier verschiedene Gründe für die Entfernung aus dem Cache angeben kann. Tabelle 15.4 nennt die möglichen Werte.
| Wert
|
Bedeutung
|
| DependencyChanged
|
Das Element wird entfernt, da eine der definierten Abhängigkeiten sich geändert hat. Beispiel: Die verknüpfte Datei hat sich geändert.
|
| Expired
|
Die Gültigkeit ist abgelaufen.
|
| Removed
|
Die Removed-Methode wurde aufgerufen oder es wurde ein neuer Eintrag mit dem gleichen Schlüssel definiert.
|
| Underused
|
Der Eintrag wurde gelöscht, weil das System Arbeitsspeicher benötigt hat.
|
Tabelle 15.4 Die Werte der Enumeration CacheItemRemovedReason
cache_10.aspx definiert innerhalb dieser Prozedur die nötigen Schritte, um eine Logdatei zu führen. Wann immer ein Eintrag aus dem Cache gelöscht wird, fügt die Prozedur in der Logdatei eine Zeile an. Dabei hält sie den Zeitpunkt, den Wert des Schlüssels, den Inhalt des Objekts und den Grund für das Löschen fest.
Public Sub RemovedFromCache _
(key As String, _
value As Object, _
reason As CacheItemRemovedReason )
Dim w As System.IO.StreamWriter
w = new System.IO.StreamWriter _
("c:\\cachelog.txt", true)
w.WriteLine(DateTime.Now.ToString() _
& " " _
& key _
& ": " _
& value.ToString() _
& " – " _
& reason.ToString())
w.Close()
End Sub
Die Ereignisprozedur mit dem Ereignis verknüpfen
Im umgebenden script-Block von cache_10.aspx wird zunächst die lokale, statische Variable onRemove als CacheItemRemovedCallback-Objekt deklariert. In der Prozedur btnOK_Click wird jeweils der Cache aktualisiert. Hier erhält die Variable onRemove mit Hilfe des AddressOf-Operators die Adresse der Prozedur RemovedFromCache als Wert. Damit können Sie beim Aufruf der Methode Cache.Insert die Variable onRemove als Parameter übergeben und haben so das Ereignis erfolgreich mit der Ereignisprozedur verknüpft.
|