Glengamoi (Forum) · AspHeute · .NET Heute (RSS-Suche) · AspxFiles (Wiki) · .NET Blogs
ASP German Homepage Homepage
 

Liste

.NET 2.0 (1)
.NET Allgemein (16)
.NET Fu (5)
ADO.NET (11)
Aprilscherz (3)
ASP Grundlagen (44)
ASP Tricks (83)
ASP.NET (44)
ASPIntranet.de (5)
C# (28)
Datenbank (44)
Dokumentation (4)
IIS 6.0 (1)
Komponenten (29)
Optimierung (10)
Server (21)
Sicherheit (34)
Tee Off (6)
VB.NET (6)
WAP (8)
Web Services (11)
XML (9)

RSS 2.0 - Die neuesten fünf Artikel auf AspHeute.com


 

Suchen





 

English Articles
Chinese Articles
Unsere Autoren
 
Link zu AspHeute
Impressum
Werben
Anfragen

Session State bei parallelen Browser-Frames und Fenstern

Geschrieben von: Christian Koller
Kategorie: ASP Tricks

Das Session Objekt und der Session State in ASP sind vielfältig einsetzbar. Sei es nun zur Absicherung eines Administrationsbereiches einer Website, zur Identifikation von Benützern allgemein, zum Personalisieren von Sites oder einfach nur zum Speichern von Userbezogenen Daten und Ergebnissen für die Dauer eines Websitebesuches.

Wie manch einer schon mit Bedauern feststellen mußte, funktioniert eine Session nur dann sehr gut, wenn der User von einer einfachen Seite zur nächsten Seite geht. Arbeitet man jedoch mit Framesets, so taucht ein Problem auf. Wird in einer ASP-Seite, die Bestandteil eines Framesets ist, der Session Variablen ein Wert zugewiesen, so ist dieser Wert in einer anderen ASP-Seite des Framesets nicht auslesbar.

Was ist der Grund für dieses Verhalten?

Das Session Objekt identifiziert den Besucher, wie im Artikel Session Variablen - Verwendung und Stolpersteine beschrieben, über einen temporären Cookie, der während des Besuches der Website vom Browser gespeichert wird.

Viele Browser, wie Microsoft Internet Explorer 4.x und 5.0, speichern einen temporären Cookie (wie den Session Cookie) im Speicher des Prozesses, der die Webseite gerade anzeigt. Bei einem Frameset wird jeder Frame von einem eigenen Prozeß verwaltet und daher hat auch jeder Frame seine eigenen temporären Cookies. So schickt auch der Webserver beim Aufruf mehrerer ASP Seiten im Frameset zu jeder ASP Seite einen eigenen Session Cookie mit und generiert für jede ASP Seite ein eigenes Session Objekt. Das ist der Grund dafür, daß man von einer ASP Seite des Framesets keinen Zugriff auf Session Variablen einer anderen ASP Seite des Framesets mehr hat. (Vergleiche auch MSDN Artikel "Session Variables Lost When ASP is Located in Frameset")

Noch komplexer wird die Problematik, wenn man unterschiedliche Frame-Seiten nicht nacheinander aufruft, sondern quasi gleichzeitig. Dies ist im speziellen der Fall, wenn das Frameset das erste Mal geladen wird. Es ist möglich, daß zuerst die ASP-Seite Nr. 1 geladen wird und dann die ASP-Seite Nr. 2. Auch der umgekehrte Fall ist möglich. Es ist sogar wahrscheinlich, daß der Browser beide Seiten parallel vom Webserver lädt.

Wie läßt sich nun dieses Problem lösen?

Folgende Ansätze bieten sich an, um Session Informationen für alle ASP-Seiten im Frameset verfügbar zu machen:

  1. Werte in Cookies anstatt in Session Variablen speichern
  2. Simulieren eines Session States mit QueryStrings

1. Werte in Cookies anstatt in Session Variablen speichern

Dabei speichert man keine Werte in Session Variablen, sondern direkt in Cookies, die ein definiertes "Ablaufdatum" (engl. Expiration Date) haben. Da "permanente" Cookies an einem zentralen Ort auf der Festplatte des Benutzers gespeichert werden, stehen die Cookies und deren Werte für alle ASP-Seiten der selben Website und damit auch für die ASP Seiten innerhalb eines Framesets zur Verfügung.

Wenn man sichergehen möchte, daß die Cookies bereits vor dem Laden der einzelnen Frames gesetzt sind und somit allen ASP-Dateien im Frameset zur Verfügung stehen, ist es ratsam, die Cookies bereits in der Frameset-Hauptseite zu setzen. Die Frameset-Hauptseite muß dazu natürlich auch eine ASP-Seite sein.

Wenn man also bisher einen Wert in einer Session Variablen gespeichert hat, so setzt man dazu nun einen Wert für einen Cookie.

Vorher: Zuweisen eines Wertes zu einer Session Variablen.

Session("VariablenName") = Wert

Jetzt: Setzen eines Wertes für einen permanenten Cookie (mit Ablaufdatum).

Response.Cookies("VariablenName") = Wert
' ### Ablaufdatum auf 24 Stunden von jetzt setzen:
Response.Cookies("VariablenName").Expires = Now() + 1

Achtung: Da der IIS den Cookie als HTTP Header zum Browser schickt muß dieser Befehl ausgeführt werden, bevor ein normaler Webseiteninhalt zum Browser übertragen wird. Dafür gibt es 2 Möglichkeiten:

  1. Ausführen des Befehls vor jedem HTML oder Response.Write Befehl.
  2. Setzen des Output Buffers am Webserver durch Response.Buffer = True am Anfang der ASP Seite (unter IIS 5.0 ist der Output Buffer standardmäßig eingeschalten).

Anmerkung: Natürlich lassen sich in Cookies keine Objekte (wie Recordsets, Connections oder Dictionary Objekte) speichern.

Wie liest man nun den Wert des Cookies wieder aus?

Bisher: Auslesen eines Wertes aus einer Session Variablen.

Wert = Session("VariablenName")

Stattdessen: Das Auslesen eines Cookie-Wertes.

Wert = Request.Cookies("VariablenName")

Vorteile dieser Methode: Wenig Programmieraufwand. Man kann bestehende ASP-Seiten einfach umschreiben.

Nachteile: Man kann einen Cookie-Wert nur dann an beliebiger Stelle im Script setzen, wenn man den Output Buffer des Webservers für die ASP-Seite aktiviert hat.
Die Werte der Cookies bleiben auch gespeichert, wenn der Benutzer alle Browserfenster geschlossen hat. Daher dauert die Session nicht 20 Minuten bzw. bis zum Schließen aller Browserfenster, sondern bis zum Ablauf des Gültigkeitsdatums des Cookies.

2. Simulieren eines Session States mit QueryStrings

Da manche Benutzer immer noch Abneigungen gegen Cookies haben, bleibt oftmals nur die Möglichkeit, für einen Benutzer während seines Besuches der Website eine Identifikationsnummer (ähnlich wie ein Session Cookie) im QueryString der URL mitzuführen.

Man kann dann Werte für diesen Benutzer für die Dauer seines Besuches in einer Datenbank oder in Application Variablen speichern und anhand der Identifikationsnummer eindeutig dem Benutzer (und seiner Session) zuordnen.

Wie funktioniert nun der Trick mit dem QueryString genau?

Ein QueryString ist nichts anderes als eine Zeichenkette, die mit einem Fragezeichen (?) beginnt und an die URL (Adresse der Webseite) angehängt wird. Der QueryString enthält dann ein oder mehrere Paare von Namen und Werten.

Für unser spezielles Problem ist es zielführend im QueryString die Identifikationsnummer für den Besucher speichern. Eine URL mit QueryString (fett) könnte also folgendermaßen aussehen:

http://www.aspheute.com/Seite.asp?IdNr=12345

Wenn der Besucher das erste Mal auf eine Seite der Website kommt, so hat er noch keinen (oder möglicherweise einen alten) QueryString in der aufrufenden URL.
Daher müssen beim Aufruf einer beliebigen ASP-Seite immer folgende Schritte gesetzt werden:

  • Prüfen, ob die URL der aufgerufenen Seite eine Identifikationsnummer (IdNr) im QueryString enthält.
  • Auslesen der Identifikationsnummer aus dem QueryString und speichern in einer ASP Variablen (z.B. SessionIdNr)
  • Liegt keine (oder eine ungültige) Id vor, so wird eine neue Id generiert und in einer ASP Variablen (SessionIdNr) gespeichert.

In der ASP Seite selbst sind folgende Dinge wichtig:

  • Jeder Link der auf die eigenen Website verweist muß im QueryString der URL die Identifikationsnummer aus der ASP Variablen (z.B. SessionIdNr) enthalten (dies gilt stenggenommen nicht für URLs von statischen .htm/.html Seiten und Grafiken). Dabei ist es egal, ob es sich um einen Textlink, Bild-Link, URL in Response.Redirect, Link in JavaScript (statisch und dynamisch), Frame URLs oder URLs in Formularen handelt.
  • Die Funktionen, die anhand der Identifikationsnummer das "Speichern" und "Auslesen" von session-spezifischen Werten aus einer Datenbank oder aus Application Variablen erlauben, müßen in jeder ASP Seite, die Zugriff auf diese Werte nehmen will, verfügbar sein. Die einfachste Lösung ist es, die Funktionen in einer eigenen ASP Datei zu definieren und mittels Inlcude Direktive in jede ASP Seite einzubinden.

Weiters ist zu beachten:

Der Mechanismus, der für das "Zuweisen" und "Lesen" der Variablen zuständig ist, muß effizient programmiert sein um den Webserver nicht zu sehr zu belasten.

Wenn auf Werte eines bestimmten Benutzers eine definierte Zeitdauer lang nicht mehr zugegriffen wurde, so sind alle gespeicherten Werte der Benutzer Session zu löschen. Ansonsten würde die Datenbank (oder das Application Objekt) in einer riesigen, speicherfressenden Sammlung von nicht mehr benötigten Daten enden.

Beispiel für den QueryString Mechanismus

Im folgenden skizziere ich die Implementation des QueryString Mechanismus, wie also eine Benutzer ID generiert und von Seite zu Seite weitergegeben wird.

Einfache ASP Seite

Die folgende Beispielseite, die auch Teil eines Framesets sein kann, liest die Benutzer ID aus dem QueryString, speichert den Wert in einer Variablen und hängt dann die Benutzer ID an jede auf der Seite vorkommende URL im QueryString an.

<%
SessionIdNr = Request.QueryString("IdNr")

If SessionIdNr = "" Then
   ' ### Keine Id im QueryString, 
   ' ### generiere Id
   SessionIdNr = Session.SessionID
End If
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

<html>
<head>
	<title></title>
</head>

<body>

<!-- Textlink -->
Klicken Sie 
<a href="seite1.asp?IdNr=<%= SessionIdNr %>">hier</a>
<br>

<!-- Textlink, der bereits Werte im QueryString hat -->
<a href="seite2.asp?Name=Wert&IdNr=<%= SessionIdNr %>">
Neue Seite</a>
<br>

<!-- Link bei einem Image Tag -->
<a href="seite3.asp?IdNr=<%= SessionIdNr %>">
<img src="bild.png" border=0 alt=""></a>

<!-- Formular mit POST -->
<form action="seite5.asp?IdNr=<%= SessionIdNr %>" method="POST">
<input type="Text" name="Name"><br>
<input type="Submit" name="Submit" value="Absenden">
</form>
<br>

<!-- Formular mit GET -->
<form action="seite6.asp" method="GET">
<input type="Hidden" name="IdNr" value="<%= SessionIdNr %>">
<input type="Text" name="Name"><br>
<input type="Submit" name="Submit" value="Absenden">
</form>
<br>

<!-- Link in einem JavaScript Event -->
<a onClick="window.open('seite4.asp?IdNr=<%= SessionIdNr %>');">
Neues Fenster</a>

</body>
</html>

Das Skript beinhaltet die folgenden Operationen:

Die IdNr aus dem QueryString wird mit Hilfe der QueryString Collection des Request Objektes ausgelesen.

Wenn Sie eine neue Id generieren, so können Sie den Wert aus Session.SessionID nur dann verwenden, wenn sie die Werte für die Session des Benutzers im Application Object speichern.

Speichern Sie allerdings die Session Werte in einer Datenbank, so sollten Sie die eindeutige Id von der Datenbank selbst generieren lassen. Microsoft SQL Server 7.0 oder Access 2000 Datenbanken stellen zu diesem Zweck die Identity bzw. Autonumber Felder zur Verfügung (Siehe auch Artikel Zugriff auf autom. generierte ID beim Einfügen eines Datensatzes). Sonst kann es passieren, wenn der Webserver kurzzeitig ausfällt oder die Webserver Applikation einen Neustart durchführt, daß eine SessionID generiert wird, die bereits von einem anderen Benutzer gehalten wird. Damit ist die "Id" nicht mehr eindeutig und das Chaos wäre perfekt.

In gewöhnlichen Links wird einfach der Wert aus der Variablen SessionIdNr im QueryString unter dem Namen IdNr angehängt.

In Formularen, die mit POST geschickt werden, wird der Wert der Variablen SessionIdNr im QueryString der Empfänger URL (Parameter Action im <FORM> Tag) unter dem Namen IdNr angehängt.

Bei Formularen, die mittels GET zum Webserver gesendet werden, ist es nötig, ein verborgenes Feld (engl. Hidden Field) in das Formular (zwischen <FORM> und </FORM>) einzufügen. Dieses Feld bewirkt, daß der Name und der Wert des Feldes zum Webserver geschickt werden:

<input type="Hidden" name="IdNr" value="<%= SessionIdNr %>">

Was dieses Beispiel nicht zeigt ist, wie man nun, anhand dieser Benutzer Id, Zugriff auf Werte der Benutzer Session erhält. Die von Seite zu Seite weitergegebene Benutzer Id (IdNr im QueryString, SessionIdNr im ASP Skript) identifiziert den Benutzer eindeutig. Anhand dieser eindeutigen Id kann man nun Werte in einer Datenbank oder in der Application Variablen speichern und wieder auslesen. Die genaue Beschreibung der Implementation solch eines Algorithmus in ASP würde allerdings den Rahmen dieses Artikels sprengen. Insbesondere ist darauf zu achten, daß Daten von inaktiven Benutzer-Sessions nach einer bestimmten Zeit gelöscht werden um Speicherplatz fressenden Datenmüll zu vermeiden.

Frameset

Um in einem Frameset die Benutzer ID an die Unter-Frames weiterzugeben, fügt man in die Benutzer ID nach bekanntem Muster in alle QueryStrings der URL (in den SRC Parametern der <Frame> Tags) ein:

<%
SessionIdNr = Request.QueryString("IdNr")

If SessionIdNr = "" Then
   ' ### Keine Id im QueryString, 
   ' ### generiere Id
   SessionIdNr = Session.SessionID
End If
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

<html>
<head>
	<title>Frameset</title>
</head>

<!-- frames -->
<frameset  rows="50%,*">
    <frame name="Frame 1" src="frame1.asp?IdNr=<%= SessionIdNr %>">
    <frame name="Frame 2" src="frame2.asp?IdNr=<%= SessionIdNr %>">
</frameset>
</html>

Die Vorteile des QueryString Mechanismus: Der simulierte Session State bleibt nur für die Dauer des Besuches erhalten. Es werden keine Cookies gesetzt.

Nachteile: Der Programmieraufwand ist sehr groß. Zum einen muß an jeden Link (ob Textlink, Link hinter einem Bild, JavaScript Link, oder Link in einem Formular) dynamisch ein QueryString angehängt werden. Daher müßen alle Seiten, die Links (oder Formulare) enthalten, ASP Seiten sein, ansonsten lassen sich die im QueryString gespeicherten Werte nicht dynamisch auslesen und in Links einfügen. Weiters muß man für das Management der Benutzersessions (und der während der Session gespeicherten Benutzer Werte) die Funktionalität selber implementieren. Dies erfordert, je nach Ansatz, fundiertes Wissen über das Application Objekt, über Datenbanken oder andere Möglichkeiten, Daten so zu speichern, daß der Webserver unter Angabe der Benutzer ID und des Variablennamens einen Zugriff auf den zugehörigen Wert der Benutzer Session hat.

Schlußbemerkung

Der Verzicht auf den Einsatz des Session Objektes in Webprojekten mit Frames ist ein immer wieder auftauchendes und ernstes Problem. Die Möglichkeiten, diese Browserunzulänglichkeiten zu umgehen, sind vielfältig. In diesem Artikel wurden das Speichern von Session Werten als Cookie Werte sowie das Mitführen einer Benutzer Id im QueryString aller URLs der Website dargestellt.

Download des Codes

Klicken Sie hier, um den Download zu starten.

Verwandte Artikel

Redirects mit Frame-Targets
Session Variablen - Verwendung und Stolpersteine
Zugriff auf autom. generierte ID beim Einfügen eines Datensatzes

Links zu anderen Sites

Session Variables Lost When ASP is Located in Frameset

Wenn Sie jetzt Fragen haben...

Wenn Sie Fragen rund um die in diesem Artikel vorgestellte Technologie haben, dann schauen Sie einfach bei uns in den Community Foren der deutschen .NET Community vorbei. Die Teilnehmer helfen Ihnen gerne, wenn Sie sich zur im Artikel vorgestellten Technologie weiterbilden möchten.

Haben Sie Fragen die sich direkt auf den Inhalt des Artikels beziehen, dann schreiben Sie dem Autor! Unsere Autoren freuen sich über Feedback zu ihren Artikeln. Ein einfacher Klick auf die Autor kontaktieren Schaltfläche (weiter unten) und schon haben Sie ein für diesen Artikel personalisiertes Anfrageformular.

 

Und zu guter Letzt möchten wir Sie bitten, den Artikel zu bewerten. Damit helfen Sie uns, die Qualität der Artikel zu verbessern - und anderen Lesern bei der Auswahl der Artikel, die sie lesen sollten.

Bewerten Sie diesen Artikel
 Sehr gut   Nicht genügend  
   1  2  3  4  5  
 

  
   Für Ausdruck optimierte Seite

©2000-2006 AspHeute.com
Alle Rechte vorbehalten. Der Inhalt dieser Seiten ist urheberrechtlich geschützt.
Eine Übernahme von Texten (auch nur auszugsweise) oder Graphiken bedarf unserer schriftlichen Zustimmung.