11.3 Der Status einer Sitzung: Session
 
Was ist eine Sitzung? Ein Anwender ruft mit seinem Browser eine Website auf. Er sieht sich einige Seiten an, gibt vielleicht irgendwelche Daten ein und verlässt die Website schließlich wieder. Das ist eine Sitzung, auf englisch Session. Aus der Sicht des Anwenders handelt es sich um eine Folge zusammenhängender Seitenaufrufe. Für den Server ist dieser Zusammenhang nicht auf Anhieb ersichtlich. Er wird künstlich durch die Verwaltung von Zustandsinformationen hergestellt.
11.3.1 Die Klasse HttpSessionState
 
ASP.NET ermöglicht die Sitzungsverfolgung mit Hilfe einer Collection vom Typ HttpSessionState, die das Page-Objekt über seine Eigenschaft Session zur Verfügung stellt. Mit der Abfrage
If Session.IsNewSession
kann ein Skript prüfen, ob mit dem aktuellen Seitenaufruf eine neue Session beginnt, und entsprechend reagieren. Wenn der Anwender seinen Namen beispielsweise in das Eingabefeld txtName eingibt, kann dieser Name in einer Session-Variablen gespeichert werden:
Session("Anwendername") = txtName.value
Damit steht der Name allen anderen Seiten zur Verfügung und kann dort aufgerufen werden, beispielsweise so:
Hallo <% = Session("Anwendername") %>
Tabelle 11.2 listet die verfügbaren Eigenschaften und Methoden von HttpSessionState auf.
Je nachdem, ob ein Seitenaufruf zu einer laufenden Session gehört oder ob eine neue Sitzung beginnt, kann eine Seite ein völlig unterschiedliches Verhalten zeigen. Die Seiten session01.aspx und session02.aspx demonstrieren dieses Verhalten. Die Startseite session01.aspx bietet dem Neueinsteiger eine Anmeldemöglichkeit (siehe Abbildung 11.2). Wenn die Startseite jedoch während einer bereits laufenden Session erneut aufgerufen wird, erscheint eine andere Meldung (siehe Abbildung 11.4). Die Seite session02.aspx wertet ebenfalls eine Session-Variable aus (siehe Abbildung 11.3).
 Hier klicken, um das Bild zu Vergrößern
Abbildung 11.2 Weil eine neue Session beginnt, bietet die Startseite eine Anmeldemöglichkeit.
<!-- session01.aspx -->
<%@ Page Language="VB" Debug="True" Strict="True" %>
<script runat="server">
Sub Page_Load (ByVal Sender As Object, _
ByVal E As EventArgs)
If Session.IsNewSession Then
neueSession.Visible = true
bekannteSession.Visible = False
Else
neueSession.Visible = False
bekannteSession.Visible = True
End If
If IsPostBack Then
Session("Anwendername") = txtName.value
ausgabe.innerText = "Hallo " & _
CStr(Session("Anwendername")) & "!" End If
End Sub
</script>
<html><head><title>Session-Demo</title></head>
<body><h3>Session-Demo</h3>
<div id="neueSession" runat="server">
<form runat="server" id="myForm">
Ich kenne Sie noch nicht. Wie heißen Sie?
<input type="text" id="txtName" runat="server">
<input type="submit" id="btnOK" runat="server"
value="OK" >
<p id="ausgabe" runat="server" />
</form>
</div>
<div id="bekannteSession" runat="server">
<p>Hallo, <% = session("Anwendername") %>, auch mal
wieder auf der Startseite zu Besuch?</p>
</div>
<p><a href="session02.aspx">Zur zweiten Seite</a></p>
</body></html>
 Hier klicken, um das Bild zu Vergrößern
Abbildung 11.3 Folgeseiten werten Session-Variablen aus.
session02.aspx wertet eine Session-Variable aus.
<!-- session02.aspx -->
<%@ Page Language="VB" Debug="True" Strict="True" %>
<script runat="server">
Sub Page_Load (ByVal Sender As Object, _
ByVal E As EventArgs)
ausgabe.innerText = CStr(Session("Anwendername")) _
& ", Du bist hier auf der zweiten Seite."
End Sub
</script>
<html><head>
<title>Session-Demo, zweite Seite</title></head>
<body><h3>Session-Demo, zweite Seite</h3>
<p id="ausgabe" runat="server" />
<p><a href="session01.aspx">Zur Startseite</a>
</body></html>
 Hier klicken, um das Bild zu Vergrößern
Abbildung 11.4 Beim wiederholten Besuch blendet die Startseite die Anmeldemöglichkeit aus.
| Name
|
Typ
|
Beschreibung
|
| Eigenschaften
|
| Contents
|
HttpSessionState
|
Existiert nur, um Kompatibilität zu früheren ASP-Versionen zu bieten
|
| Count
|
Integer
|
Anzahl der gespeicherten Session-Variablen
|
| IsCookieless
|
Boolean
|
True, wenn die Session-ID in den URL eingebettet wird, sonst False
|
| IsNewSession
|
Boolean
|
True, wenn die Sitzung mit der aktuellen Anforderung beginnt
|
| IsReadOnly
|
Boolean
|
True, wenn die Sitzung schreibgeschützt ist
|
| Item(String) oder Item(Integer)
|
Object
|
Ruft den Wert einer Session-Variablen über den Bezeichner oder über den numerischen Index auf
|
| Keys
|
NameObjectCollectionBase.KeysCollection
|
Auflistung aller gespeicherten Schlüssel
|
| Mode
|
SessionStateMode
|
Möglichkeiten sind InProc, Off, SQLServer und StateServer
|
| SessionID
|
String
|
Session-ID
|
| StaticObjects
|
HttpStaticObjectsCollection
|
Auflistung von Objekten, die durch <object Runat="Server" Scope="Session"/>-Tags innerhalb von global.asax deklariert werden
|
| Timeout
|
Integer
|
Anzahl der Minuten, nach denen eine Sitzung verfällt
|
| Methoden
|
| Abandon()
|
Bricht die aktuelle Sitzung ab. Nur bei mode="InProc" verfügbar
|
| Add (String, Object)
|
Speichert eine neue Session-Variable
|
| Clear()
|
Löscht alle Session-Variablen
|
| CopyTo(Array, Integer)
|
Kopiert die Session-Variablen in ein eindimensionales Array
|
| GetEnumerator()
|
Enumerator für alle Session-Variablen
|
| Remove(String)
|
Löscht die Session-Variablen mit dem Schlüssel, der im String übergeben wird
|
| RemoveAll()
|
Löscht alle Session-Variablen
|
| RemoveAt(Integer)
|
Löscht die Session-Variable an der angegeben Indexposition
|
Tabelle 11.2 Mitglieder der Klasse HttpSessionState
11.3.2 Wie ASP.NET die Probleme des klassischen ASP löst
 
Im Vergleich zum klassischen ASP bietet ASP.NET für die Sitzungsverfolgung eine Reihe neuer Möglichkeiten. Diese lassen sich am besten verstehen, wenn man die Probleme kennt, die das klassische ASP mit der Sitzungsverfolgung hatte. Ein Teil dieser Probleme resultierte aus der Arbeitsweise des Servers. Ein anderer Teil wurde durch die Art der Kommunikation mit dem Client verursacht.
Die Probleme auf der Serverseite resultierten daraus, dass ASP die Session-Variablen ausschließlich im Arbeitsspeicher des Webservers hielt. Daraus ergaben sich zwei Probleme:
1. Wenn die Server-Hard- oder Software abstürzte, waren alle Session-Daten rettungslos verloren. Die Dauerhaftigkeit der Daten war nicht gesichert.
2. Weil die Session-Daten nur im Adressraum einer einzelnen Maschine zur Verfügung standen, konnten Sessions nicht für Webfarmen verwendet werden. In Webfarmen werden mehrere Server zu einem Verbund zusammengeschlossen, um die anfallende Masse von Anfragen besser beantworten zu können.
Das Problem in der Kommunikation mit dem Client bestand darin, dass ASP für die Session-Verwaltung auf Cookies angewiesen war. Wenn nicht alle Firewalls Cookies passieren ließen und nicht alle Browser Cookies unterstützten, scheiterte die ASP-Session-Verwaltung.
ASP.NET löst diese Probleme. Der folgende Abschnitt 11.3.3, Übertragung der Session-ID: Cookie oder URL, demonstriert genauer, wie ASP.NET das Problem mit den Cookies löst. Die Session-ID kann jetzt statt über Cookies auch über den URL transportiert werden. Diese Variante kann weder von Firewalls noch von Browsern behindert werden, denn der URL ist das grundlegende Zahnrad der ganzen Internetmaschinerie.
Für die Lösung der serverseitigen Probleme ermöglicht es ASP.NET, die Session-Daten aus dem Serverprozess auszugliedern und in einem externen Prozess zu speichern. Genauer gesagt, bietet ASP.NET hier zwei Möglichkeiten:
1. Der Sitzungsstatus kann in einem speziellen Statusprozess gespeichert werden, der als NT-Dienst zur Verfügung gestellt wird. Dieser Dienst kann auf dem gleichen Rechner wie der Webserver oder auf einem anderen Rechner laufen, und er kann mehrere Webserver »bedienen«. Vorteil: Nach einem Absturz des Webservers sind die Sitzungs-Informationen noch immer vorhanden. Nachteil: Wenn der Session-Dienst selbst abstürzt, sind die Sitzungsinformationen verloren.
2. Wenn die Sitzungsverwaltung auch einen »Totalschaden« überleben soll, können die Sitzungsdaten dauerhaft in einem SQL Server gespeichert werden.
Beide Methoden sollten wohl überlegt zum Einsatz kommen. Auf der einen Seite gewinnt die Applikation durch die externe Speicherung der Sitzungsinformationen an Stabilität. Andererseits sind Zugriffe auf externe Prozesse stets aufwendiger als prozessinterne Abläufe, so dass mit einer schlechteren Performance zu rechnen ist.
Aus den genannten neuen Möglichkeiten resultieren im Wesentlichen zwei Ergebnisse:
1. Aufgrund der Unabhängigkeit von Browsern und Firewalls ist die Sitzungsverwaltung von ASP.NET universell einsetzbar.
2. Wegen der externen Speicherung der Sitzungsinformationen ist ASP.NET gut skalierbar.
Der Abschnitt 11.3.5, Den Sitzungsstatus konfigurieren, informiert detailliert über die Möglichkeit, den Sitzungsstatus zu konfigurieren.
11.3.3 Übertragung der Session-ID: Cookie oder URL
 
Woher weiß der Server, zu welcher Session ein Seitenaufruf gehört? Jede Sitzung wird über eine eindeutige Session-ID identifiziert. Diese Session-ID muss der Browser stets dem Server übermitteln. Dafür bietet ASP.NET zwei Möglichkeiten:
|
Als Standard verwendet ASP.NET für die Übermittlung der Session-Id Cookies. Das war auch beim klassischen ASP bislang die einzige Möglichkeit. |
|
Neu hinzugekommen ist die Möglichkeit, die Session-ID in den URL einzubetten. |
Die verwendete Methode stellen Sie mit Hilfe der Datei web.config ein. Wenn Sie Cookies vermeiden möchten, nehmen Sie in web.config einen entsprechenden Eintrag vor:
<configuration>
<system.web>
<sessionState cookieless="true" />
...
</system.web>
</configuration>
Wenn Sie diese Änderung eingeben und anschließend die Beispielseite session01.aspx erneut aufrufen, erkennen Sie den Unterschied. Abbildung 11.5 zeigt ein Beispiel. ASP.NET fügt bei jedem Seitenaufruf die Session-ID als Pfadbezeichner vor den eigentlichen Seitennamen ein. Die URL-Zeile gewinnt damit beispielsweise diese Form:
http://localhost/ASPdotNETBuch/(yut0peqswve15a45hx1mqp55)/Listings/session01.aspx
 Hier klicken, um das Bild zu Vergrößern
Abbildung 11.5 Für Sessions ist ASP.NET nicht auf Cookies angewiesen. Die Session-ID kann alternativ in die URL-Zeile eingebettet werden.
Auf diese Weise können Sie Sitzungen auch dann verfolgen, wenn ein Browser Cookies deaktiviert hat oder wenn eine Firewall keine Cookies passieren lässt.
Wenn Sie keine Cookies verwenden, müssen Sie bei Links darauf achten, dass Sie innerhalb Ihrer Applikation nur relative Links verwenden. Diesen Link setzt ASP.NET korrekt um:
<a href="session02.aspx">
ASP.NET kann hier die Session-ID in den URL einbetten und im Browser erscheint korrekt ein Sprung zu
http://localhost/ASPdotNETBuch/(5kx35545ahmr1datkr0aba45)/Listings/session02.aspx
Dieser Link funktioniert nicht korrekt:
<a href="http://localhost/
ASPdotNETBuch/Listings/session02.aspx">
In diesen hart codierten Link kann ASP.NET die benötigte Session-ID nicht einbetten. Die benötigten Session-Variablen stünden anschließend nicht mehr zur Verfügung.
| Tipp Wenn Sie dennoch komplette Pfade angeben möchten, bietet die Methode ApplyAppPathModifier der HttpResponse-Klasse die Möglichkeit, den kompletten Aufruf wenigstens manuell zu erzeugen.
|
tmp = Response.ApplyAppPathModifier("session01.aspx")
Dieser Funktionsaufruf gibt beispielsweise folgenden String zurück:
/ASPdotNETBuch/(jbbp0cmp22bkrkbn0kdw5n3a)/Listings/
session01.aspx
Anschließend können Sie diesen String in dynamisch erzeugten Links verwenden.
| Achtung ASP.NET verwendet für die Sitzungsverfolgung entweder die Cookie- oder die URL-Methode. Wenn Ihre Applikation für die Übermittlung der Session-ID Cookies verwendet, schaltet ASP.NET nicht automatisch auf die URL-Einbettungsmethode um, wenn ein Browser keine Cookies akzeptiert. In diesem Fall würde die Applikation nicht funktionieren.
|
Die URL-Methode wird nur dann verwendet, wenn Sie das in der web.config-Datei ausdrücklich angeben. Wenn also die Möglichkeit besteht, dass irgendein Aufrufer mit Cookies nicht zurechtkommt, dann müssen Sie von vornherein Cookies ausschalten und generell mit der URL-Methode arbeiten.
11.3.4 Den Sitzungsstatus ein- und ausschalten
 
Wenn Ihre Webapplikation keine Sessions benötigt, dann sollten Sie die Unterstützung für Sessions ausdrücklich abschalten, denn damit schonen Sie die Ressourcen des Servers. In einem anderen Fall benötigen vielleicht nur einzelne Seiten den Zugriff auf Sitzungsdaten. Für andere Seiten sind die Sitzungsdaten dagegen unerheblich. Die Unterstützung für Sessions können Sie an verschiedenen Stellen ein- oder ausschalten. In den Dateien machine.config und web.config ist es zunächst möglich, eine Voreinstellung für alle Seiten vorzunehmen. Der folgende Eintrag in der Datei web.config aktiviert Sessions für alle Seiten als Default-Einstellung:
<configuration>
<system.web>
<pages enableSessionState="true" />
...
</system.web>
</configuration>
Das Attribut enableSessionState verfügt über drei mögliche Werte: true, false und ReadOnly. Der Wert in der Datei web.config kann von jeder aspx-Seite in der Page-Direktive überschrieben werden. Wenn eine bestimmte Seite keine Sessions unterstützen soll, muss die Page-Direktive einen entsprechenden Eintrag enthalten:
<%@ Page EnableSessionState="false" %>
Wenn während einer laufenden Sitzung auf diese Seite zugegriffen wird, dann wird die Sitzung nicht ungültig, aber innerhalb dieser Seite kann nicht auf Session-Variablen zugegriffen werden. Entsprechend verhält sich die Option enableSessionState="ReadOnly". In diesem Fall können Session-Variablen gelesen, aber nicht neu definiert werden.
Die Beispielseiten session03.aspx und session04.aspx verdeutlichen, wie Seiten mit und ohne Sessions nebeneinander existieren können. session03.aspx setzt EnableSessionState="false". session04.aspx setzt EnableSessionState="true". Beim Aufruf von session03.aspx wird keine Session angelegt. Beim Sprung zu session04.aspx wird eine Session angelegt. Beim Rücksprung zu session03.aspx bleibt die Session erhalten, die Seite kann aber die Session-Daten nicht auswerten. Wenn man bei diesem Beispiel die Session-ID über den URL transportieren lässt, wird deutlich, wann keine Session existiert, wann sie angelegt wird und ob sie erhalten bleibt. Abbildung 11.6 bis Abbildung 11.8 zeigen die Schritte.
 Hier klicken, um das Bild zu Vergrößern
Abbildung 11.6 Beim ersten Aufruf der Seite ohne Session-Unterstützung wird keine Session angelegt.
<!-- session03.aspx -->
<%@ Page Language="VB" Debug="True" Strict="True"
EnableSessionState="False" %>
<html><head><title>Keine Session</title></head><body>
<h3>Das ist eine Seite ohne Session-Unterstützung</h3>
<a href="session04.aspx">Zur Seite
mit Session-Unterstützung</a>
</body></html>
 Hier klicken, um das Bild zu Vergrößern
Abbildung 11.7 Beim Sprung zur Seite mit Session-Unterstützung wird eine neue Session angelegt, was an dem URL mit Session-ID zu sehen ist.
<!-- session04.aspx -->
<%@ Page Language="VB" Debug="True" Strict="True"
EnableSessionState="true" %>
<html><head><title>Mit Session</title></head><body>
<h3>Das ist eine Seite mit Session-Unterstützung</h3>
<a href="session03.aspx">Zur Seite
ohne Session-Unterstützung</a></body></html>
 Hier klicken, um das Bild zu Vergrößern
Abbildung 11.8 Beim Rücksprung zur Seite ohne Session-Unterstützung bleibt die Session dennoch erhalten.
11.3.5 Den Sitzungsstatus konfigurieren
 
In der Datei web.config stellen Sie mit dem Element sessionState ein, wie der Sitzungsstatus gespeichert werden soll. Das Element sessionState hat diese Optionen:
<sessionState mode="Off|Inproc|StateServer|SQLServer"
cookieless="true|false"
timeout="Anzahl Minuten"
stateConnectionString="tcpip=server:port"
sqlConnectionString="sql connection string"
/>
Keine Unterstützung von Sessions
Wenn Ihre Anwendung keine Sessions unterstützen soll, geben Sie dem Attribut mode den Wert Off.
Sessions im eigenen Serverprozess verwalten
Wenn Sessions innerhalb des Webserverprozesses verwaltet werden sollen, geben Sie dem Attribut mode den Wert Inproc.
Einen separaten ASP.NET-Statusdienst verwenden
Wenn Sie für die Statusverwaltung einen eigenen NT-Dienst betreiben, dann ist mode="StateServer" der passende Wert. In diesem Fall müssen Sie außerdem im Attribut stateConnectionString die IP-Adresse und Port-Nummer des Dienstes angeben. Ein Beispiel:
<sessionState
mode= "StateServer"
stateConnectionString="tcpip=127.0.0.1:42424" />
Den ASP.NET-Statusdienst starten und beenden Sie über Start • Einstellungen • Systemsteuerung • Verwaltung • Dienste (siehe Abbildung 11.9).
Den Sitzungsstatus in einem SQL Server speichern
Die High-End-Lösung für die Sitzungsverwaltung ist die Speicherung der Sitzungsdaten in einem SQL Server. Das Attribut mode benötigt in diesem Fall den Wert SQLServer. Dem Attribut sqlConnectionString müssen Sie die benötigte Verbindungszeichenfolge zuweisen. Ein Beispiel:
<sessionState
mode= "SQLServer"
sqlConnectionString=
"data source=127.0.0.1;user id=sa; password=geheim"
/>
 Hier klicken, um das Bild zu Vergrößern
Abbildung 11.9 Der ASP.NET-Statusdienst verwaltet Sessions in einem NT-Dienst, der unabhängig vom Webserver läuft.
In Ihrem SQL Server müssen Sie die entsprechenden Vorbereitungen treffen. Die benötigten Datenbanken, Tabellen und Stored Procedures legt das Skript InstallSqlState.sql für Sie an, das Sie standardmäßig im Pfad C:\WINNT\Microsoft.NET\Framework\v1.0.3705 finden.
Die Attribute cookieless und timeout bieten weitere Konfigurationsmöglichkeiten. Mit cookieless="true" werden die Session-IDs nicht über Cookies, sondern über den URL transportiert.
Mit dem timeout-Attribut stellen Sie ein, nach wie vielen Minuten eine Session verfällt.
11.3.6 Session-Ereignisse verwenden
 
Eine beginnende Sitzung löst das Ereignis Session_OnStart() aus. Wenn eine Sitzung endet, wird das Ereignis Session_OnEnd() ausgelöst. Die Klasse SessionStateModule stellt diese Ereignisse bereit. Die Ereignisprozeduren gehören in die Datei global.asax, die im Stammverzeichnis der Anwendung liegt. Hier können Sie Startwerte initialisieren und nach dem Sitzungsende Aufräumarbeiten durchführen.
Ein Beispiel soll das Verfahren illustrieren. Jede Session soll sich ihren eigenen Startzeitpunkt merken. Die Datei global.asax muss beispielsweise diese Form haben:
<script language="VB" runat="server">
Sub Session_OnStart()
Session("Startzeitpunkt") = DateTime.Now
End Sub
</script>
Mit dem Aufruf von session05.aspx beginnt eine neue Session.
<!-- session05.aspx -->
<%@ Page Language="VB" Debug="True" Strict="True" %>
<script runat="server">
Sub Page_Load (ByVal Sender As Object, _
ByVal E As EventArgs)
ausgabe.innerText = "Startpunkt der Session: " & _
CStr(Session("Startzeitpunkt"))
ausgabe2.innerText = "Jetzt ist es: " & DateTime.Now
End Sub
</script>
<html><head><title>Session_OnStart-Demo, Seite 1</title></head>
<body><h3>Session_OnStart-Demo, Seite 1</h3>
<p runat="server" id="ausgabe" />
<p runat="server" id="ausgabe2" />
<a href="session06.aspx">Zur Seite 2</a>
</body></html>
Die Seite gibt den Startzeitpunkt der Session und die aktuelle Zeit aus. Ein Link führt zur Datei session06.aspx. Diese Datei enthält die gleichen Ausgaben mit einer aktualisierten Angabe der aktuellen Zeit. Indem Sie zwischen session05.aspx und session06.aspx hin- und herspringen (Abbildung 11.10 und Abbildung 11.11), können Sie beobachten, dass beide Dateien stets die gleiche Angabe für den Startzeitpunkt und eine aktualisierte Zeitangabe ausgeben.
 Hier klicken, um das Bild zu Vergrößern
Abbildung 11.10 Über die Ereignisprozedur Session_OnStart merkt sich jede Session ihren Startzeitpunkt.
 Hier klicken, um das Bild zu Vergrößern
Abbildung 11.11 Über die Session-Variable können alle Seiten auf den Startzeitpunkt zugreifen.
<!-- session06.aspx -->
<%@ Page Language="VB" Debug="True" Strict="True" %>
<script runat="server">
Sub Page_Load (ByVal Sender As Object, _
ByVal E As EventArgs)
ausgabe.innerText = "Startpunkt der Session: " & _
CStr(Session("Startzeitpunkt"))
ausgabe2.innerText = "Jetzt ist es: " & DateTime.Now
End Sub
</script>
<html><head><title>Session_OnStart-Demo, Seite 2</title></head>
<body><h3>Session_OnStart-Demo, Seite 2</h3>
<p runat="server" id="ausgabe" />
<p runat="server" id="ausgabe2" />
<a href="session05.aspx">Zur Seite 1</a>
</body></html>
11.3.7 Objekte mit Session-Scope einbinden
 
Sie können für eine Session auch Klasseninstanzen erstellen, auf die Sie von allen Seiten aus zugreifen können. Dafür stellt die Datei global.asax das Element object zur Verfügung. Die allgemeine Syntax lautet:
<object id="myID"
runat="server"
scope="session"
class="Name der Klasse"
/>
Auch hierzu wieder ein Beispiel. In einem Objekt vom Typ StringBuilder möchten Sie die Abfolge der Seiten speichern, die ein Anwender beim Besuch Ihrer Website aufruft.
| Achtung Bevor Sie dieses Beispiel in der Praxis einsetzen, sollten Sie sich eingehend über die datenschutzrechtlichen Aspekte dieses Themas informieren. Sie verstoßen gegen das Datenschutzrecht, wenn Sie personenbezogene Daten mit Aufzeichnungen zur zurückgelegten Datenspur kombinieren. Solange die Aufzeichnungen anonym bleiben und der Anwender außerdem mit der anonymen Aufzeichnung seiner Datenspur einverstanden ist, ist das Verfahren rechtlich unbedenklich. Im konkreten Fall sollten Sie jedoch die datenschutzrechtlichen Aspekte Ihrer Anwendung von einem Experten prüfen lassen.
|
Nun aber zur technischen Umsetzung der geplanten Aufzeichnung. Sie erzeugen für jede neue Session eine Instanz vom Typ StringBuilder, indem Sie in der Datei global.asax diesen Eintrag vornehmen:
<object id="mySB"
runat="server"
scope="session"
class="System.Text.StringBuilder"
/>
Anschließend steht die Variable mySB auf allen Seiten als Eigenschaft zur Verfügung. Die Seiten session07.aspx und session08.aspx fügen die aktuelle Seite jeweils dem StringBuilder-Objekt hinzu:
mySB.append (Request.FilePath & "<br>")
Den bislang zurückgelegten Pfad geben Sie im Browser aus:
ausgabe.innerHTML = mySB.toString()
Wenn Sie zwischen session07.aspx und session08.aspx hin- und herwechseln und einige Male einen Reload einer Seite ausführen, können Sie beobachten, wie die Liste der besuchten Seiten allmählich anwächst (siehe Abbildung 11.12).
<!-- session07.aspx -->
<%@ Page Language="VB" Debug="True" Strict="True" %>
<script runat="server">
Sub Page_Load (ByVal Sender As Object, _
ByVal E As EventArgs)
mySB.append (Request.FilePath & "<br>")
ausgabe.innerHTML = mySB.toString()
End Sub
</script>
<html><head><title>
Demo zur Klasseninstanz mit Session-Scope, Seite 1
</title></head>
<body><h3>Demo zur Klasseninstanz mit Session-Scope, Seite 1</h3>
<p>Diese Session hat diesen Pfad zurückgelegt:</p>
<p runat="server" id="ausgabe" />
<a href="session08.aspx">Zur Seite 2</a>
</body></html>
Das Beispiel können Sie abrunden, indem Sie in global.asax noch die Ereignisprozedur Session_OnEnd ergänzen. Beim Abschluss einer Session könnte die aufgezeichnete Datenspur beispielsweise gespeichert werden.
 Hier klicken, um das Bild zu Vergrößern
Abbildung 11.12 In einem StringBuilder-Objekt speichert jede Session den zurückgelegten Datenpfad. Beachten Sie den Datenschutz!
11.3.8 Instanzen eigener Klassen in den Sitzungsdaten speichern
 
Sie können nicht nur Instanzen von Klassen aus dem .NET Framework, sondern auch Instanzen selbst geschriebener Klassen für die Sitzungsverfolgung nutzen. Das Beispiel aus dem vorigen Abschnitt lässt sich entsprechend erweitern, indem Sie Ihre eigene Klasse Besuchsverlauf definieren.
| Achtung Wenn Sie eine Klasse entwerfen mit dem Ziel, sie bei der Sitzungsverfolgung zu verwenden, sollten Sie darauf achten, dass die Klasse serialisierbar ist. Der Grund dafür liegt in der Art und Weise, wie die Session-Daten gespeichert werden. Solange die Session-Daten im gleichen Prozessraum wie Ihre Applikation gehalten werden, müssen die Session-Daten nicht unbedingt serialisierbar sein. Das ist der Fall, wenn der sessionState-Eintrag in der web.config das Attribut mode="InProc" enthält.
|
Sobald die Sitzungsdaten jedoch mit einem eigenen ASP.NET-Sitzungsdienst (mode="StateServer") oder mit einem SQL Server (mode="SQLServer") verwaltet werden, müssen die Daten kontinuierlich zum Verwaltungsdienst hin- und von dort aus wieder zurücktransportiert werden. Das geht nur, wenn diese Daten serialisierbar sind. Zeiger und Datei-Handles sind Beispiele nicht serialisierbarer Daten.
Das folgende Beispiel demonstriert die Verwendung einer selbst definierten Klasse bei der Sitzungsverwaltung. Die Datei Besuch.vb definiert die Klasse Besuchsverlauf. Da nur das Prinzip gezeigt werden soll, ist die Klasse denkbar schlicht. Sie stellt lediglich ein StringBuilder-Objekt und ein DateTime-Objekt als öffentliche Eigenschaften zur Verfügung.
' Besuch.vb
Imports System
Public Class Besuchsverlauf
Public mySB As New System.Text.StringBuilder()
Public myStart As System.DateTime
End Class
Kompilieren Sie diese Klasse in eine dll-Datei. Verwenden Sie dazu diesen Aufruf:
vbc /target:library Besuch.vb
Der Compiler erzeugt die Datei Besuch.dll. Diese Datei kopieren Sie in das /bin-Verzeichnis unterhalb des Stammverzeichnisses Ihrer Anwendung.
Erstellen Sie im Stammverzeichnis Ihrer Anwendung eine Datei global.asax mit diesem Inhalt:
<% @Assembly name="Besuch" %>
<object id="myVerlauf"
runat="server"
scope="session"
class="Besuchsverlauf"
/>
<script language="VB" runat="server">
Sub Session_OnStart()
myVerlauf.myStart = System.DateTime.Now
End Sub
</script>
Mit der @Assembly-Direktive machen Sie Ihre Assembly Besuch bekannt. Mit dem object-Element erzeugen Sie für jede neue Session eine Instanz der Klasse Besuchsverlauf. Beim Start einer neuen Session wird außerdem die myStart-Eigenschaft der Besuchsverlauf-Klasse initialisiert.
Nun benötigen Sie noch ein oder zwei Seiten, die Ihr Besuchsverlauf-Objekt nutzen. session09.aspx merkt sich den bisherigen Verlauf, zeigt ihn an und bietet außerdem die Möglichkeit, die Session ausdrücklich zu beenden.
<!-- session09.aspx -->
<%@ Page Language="VB" Debug="True" Strict="True" %>
<script runat="server">
Sub Page_Load (ByVal Sender As Object, _
ByVal E As EventArgs)
If IsPostBack Then
Session.Abandon()
Response.Redirect _
("http://localhost/ASPdotNETBuch/
Listings/session09.aspx")
Else
myVerlauf.mySB.append _
(Request.FilePath & "<br>")
ausgabe.innerHTML = myVerlauf.mySB.toString()
End If
End Sub
</script>
<html><head><title>
Demo zu: Instanz einer selbst definierten Klasse mit
Session-Scope, Seite 1
</title></head>
<body><h3>Demo zu: Instanz einer selbst definierten
Klasse mit Session-Scope, Seite 1</h3>
<p>Diese Session hat diesen Pfad zurückgelegt:</p>
<p runat="server" id="ausgabe" />
<a href="session10.aspx">Zur Seite 2</a>
<form runat="server">
<input type="submit" value="Session beenden"
runat="server" >
</form></body></html>
session10.aspx speichert den Verlauf und zeigt ihn an. Mit Links können Sie zwischen diesen beiden Dateien hin- und herspringen.
<!-- session10.aspx -->
<%@ Page Language="VB" Debug="True" Strict="True" %>
<script runat="server">
Sub Page_Load (ByVal Sender As Object, _
ByVal E As EventArgs)
myVerlauf.mySB.append (Request.FilePath & "<br>")
ausgabe.innerHTML = myVerlauf.mySB.toString()
End Sub
</script>
<html><head><title>
Demo zu: Instanz einer selbst definierten Klasse
mit Session-Scope, Seite 2
</title></head>
<body><h3>Demo zu: Instanz einer selbst definierten
Klasse mit Session-Scope, Seite 2</h3>
<p>Diese Session hat diesen Pfad zurückgelegt:</p>
<p runat="server" id="ausgabe" />
<a href="session09.aspx">Zur Seite 1</a>
</body></html>
Und nun müssen Sie noch darauf achten, dass die Datei web.config bei sessionState zunächst den Eintrag mode="InProc" trägt.
<configuration>
<system.web>
<pages enableSessionState="true" />
<sessionState cookieless="true"
mode="InProc" />
</system.web>
</configuration>
Rufen Sie session09.aspx im Browser auf, klicken Sie den Link Zur Seite 2 an und springen Sie einige Male zwischen den beiden Seiten hin und her. Die Liste der besuchten Seiten wird immer länger (siehe Abbildung 11.13).
Schließlich klicken Sie auf der Seite session09.aspx auf die Schaltfläche Session beenden. Anschließend wird die laufende Sitzung beendet und die Seite wird neu geladen, wodurch eine neue Session beginnt.
So weit, so gut. Und jetzt möchten Sie für die Sitzungsverfolgung den separaten ASP.NET-Statusdienst nutzen.
 Hier klicken, um das Bild zu Vergrößern
Abbildung 11.13 Hier speichern Sie den Sitzungsverlauf mit Hilfe einer selbst definierten Klasse.
Überprüfen Sie über Start • Einstellungen • Systemsteuerung • Verwaltung • Dienste, ob der ASP.NET-Statusdienst bereits läuft (siehe Abbildung 11.9). Stellen Sie dann die Datei web.config auf mode="StateServer" um:
<configuration>
<system.web>
<pages enableSessionState="true" />
<sessionState cookieless="true"
mode="StateServer"
stateConnectionString="tcpip=127.0.0.1:42424"
/>
</system.web>
</configuration>
Wenn Sie anschließend die Seite session09.aspx neu aufrufen, erscheint die in Abbildung 11.14 gezeigte Fehlermeldung.
Die Bedeutung der Fehlermeldung ist nicht auf Anhieb erkennbar. Was soll es heißen, wenn da behauptet wird Der Typ Besuchsverlauf ... ist als serialisierbar markiert? Wir haben die Klasse doch gar nicht ausdrücklich als serialisierbar markiert?! Verstehen Sie es einfach so: Die Klasse sollte entsprechend gekennzeichnet sein.
 Hier klicken, um das Bild zu Vergrößern
Abbildung 11.14 Wenn der ASP.NET-Statusdienst oder ein SQL Server die Sitzungsdaten verwaltet, müssen Session-Objekte serialisierbar sein.
Um den Fehler zu beheben, ist nur eine kleine Korrektur im Quellcode der Klasse nötig. Sie müssen vor der Klassendeklaration das Attribut Serializable angeben:
' Besuch.vb
Imports System
<Serializable()> Public Class Besuchsverlauf
Public mySB As New System.Text.StringBuilder()
Public myStart As System.DateTime
End Class
Kompilieren Sie die Klasse neu. Kopieren Sie Besuch.dll wieder in das /bin-Verzeichnis. Anschließend funktionieren die Seiten wie gewünscht.
Es würde zu weit führen, an dieser Stelle das Konzept der Serialisierbarkeit im Detail zu erläutern. Genauere Informationen dazu finden Sie etwa bei Andreas Kühnel: VB.NET.
Vorsicht vor Session_OnEnd!
Nachdem Sie diese Klippe gut umschifft haben, werden Sie vielleicht auf die Idee kommen, der Klasse eine Methode hinzuzufügen, die die gesammelten Daten speichert. Diese Methode soll stets beim Beenden einer Session aufgerufen werden. Dafür ließe sich die Ereignisprozedur Session_OnEnd einsetzen.
Gesagt, getan. In der Datei Besuch.vb ergänzen Sie innerhalb der Klasse Besuchsverlauf eine Methode Speichern, etwa so:
' Besuch.vb
Imports System
Imports System.IO
Imports System.Runtime.Serialization
<Serializable()> Public Class Besuchsverlauf
Public mySB As New System.Text.StringBuilder()
Public myStart As System.DateTime
Public Sub Speichern (ByVal inSessionID As String)
Dim datnam As String
datnam = "C:\session" & inSessionID
Dim strom As New StreamWriter(datnam)
strom.WriteLine (CStr(myStart))
strom.Write (mySB.toString())
strom.Close()
End Sub
End Class
Diese Datei kompilieren Sie und kopieren sie in das /bin-Verzeichnis.
In der Datei global.asax ergänzen Sie die Ereignisprozedur Session_OnEnd:
Sub Session_OnEnd()
myVerlauf.Speichern(Session.SessionID)
End Sub
Sie rufen session09.aspx im Browser auf, wechseln zu session10.aspx, kehren zu session09.aspx zurück und klicken dann die Schaltfläche Session beenden an. Anschließend suchen Sie im Explorer auf dem Laufwerk c: nach einer Datei, die mit session... anfängt, aber weit und breit ist nichts davon zu sehen. Wie das? Seltsamerweise ist auch kein Fehler zu bemerken.
| Achtung Des Rätsels Lösung: Das Ereignis Session_OnEnd tritt nur ein, wenn für die Sitzungsverwaltung die Option mode="InProc" gewählt wurde. Wenn Sie den separaten ASP.NET-Statusdienst oder einen SQL Server für die Sitzungsverwaltung verwenden, tritt das Session_OnEnd-Ereignis gar nicht ein. So teilt es auch die Online-Dokumentation etwas versteckt mit. Mit anderen Worten: Das Ereignis Session_OnEnd ist nicht skalierbar.
|
Probieren Sie es aus. Ändern Sie den Eintrag in der web.config wieder zurück zu mode="InProc":
<sessionState cookieless="true"
mode="InProc"
stateConnectionString="tcpip=127.0.0.1:42424" />
Das stateConnectionString-Attribut können Sie trotzdem stehen lassen, es stört nicht. Wieder ein Test: hin- und herwechseln und Session beenden anklicken. Und siehe da: Jetzt befindet sich auf Laufwerk c: die ersehnte Datei, z. B. mit dem Namen sessionlxobau45ymidcw45yhg4lx55. Wenn Sie die Datei öffnen, finden Sie darin zunächst eine Datumsangabe mit Uhrzeit und im Anschluss daran die Liste der besuchten Seiten, die jeweils mit einem <br> voneinander getrennt sind (siehe Abbildung 11.15).
 Hier klicken, um das Bild zu Vergrößern
Abbildung 11.15 Beim Beenden einer Sitzung speichern Sie den Verlauf der besuchten Seiten ab.
Damit stellt sich die Frage, wie Sie die Verlaufsdaten sichern können, wenn Sie die Sitzungsdaten extern verwalten. Im Prinzip bleibt Ihnen dann nichts anderes übrig, als den zurückgelegten Datenpfad bei jeder neu aufgerufenen Seite sofort zu speichern.
|