ASP.NET Grundlagen Teil 2: Tschüss Statuslosigkeit
Dies ist die Fortsetzung der Artikelserie "ASP.NET Grundlagen" mit folgenden Teilen:
In Teil 1 gab es einen Blick hinter die Kulissen und die Erkenntnis das es der Entwickler bei Webtechnologien mit Statuslosigkeit zu tun hat.
Es gibt jedoch Möglichkeiten um die Statuslosigkeit mehr oder weniger loszuwerden bzw. mit der Statuslosigkeit umzugehen.
Auf diese Möglichkeiten möchte ich jetzt eingehen, vorallem wann / wie / was genutzt werden kann oder sollte.
SessionState
Der SessionState bietet die Möglichkeit Benutzer über eine Sitzung weg zu identifizieren.
Dies geschieht mit der Nutzung eines temporären Cookies auf dem Computer des Benutzers,
in diesem Cookie ist eine SessionId - eine Id zur Identifikation des Benutzers am Server - gespeichert.
Die Session bleibt solange bestehen, bis das Timeout nach dem letzten Kontakt mit dem Server abgelaufen ist, oder aber das Browserfenster geschlossen wird.
Anmerkung:
Wenn das Browserfenster geschlossen wird, ist die Session clientseitig verloren, serverseitig läuft sie aber noch solange bis der Timeout abgelaufen ist. Benutzt werden kann sie nicht mehr -> Ausser bei speziellen Spezialfällen natürlich....
Anhand der SessionId können dann Daten im Arbeitsspeicher des Servers für einen Benutzer gespeichert und abgerufen werden.
Benutzt wird / sollte der SessionState primär für alles was im Benutzerkontext abläuft.
Allerdings reicht es auch hier in den meisten Fällen, bzw. ist es ratsam nur jeweils eine Identifizierung (Bentzer-Id in der Datenbank) in der Session zu speichern, da pro Benutzer gespeichert wird.
Das bedeutet - bei einer Mehrbenutzeranwendung -was ASP.NET auch ist, dass pro Benutzer jeweils Objekte im Arbeitsspeicher des Servers gehalten werden.
Diese bleiben solange im Arbeitsspeicher vorhanden, bis das Session-Timout abläuft oder aber die Daten manuell gelöscht werden.
Darum sollte darauf darauf geachtet werden, dass nur wirklich die nötigsten Daten im SessionState gehalten werden.
Nehmen wir bspw. mal eine Datenmenge von 500Kb die sich bei jedem Nutzer der Webanwendung angesammelt wird, dies bei 100 Benutzern.
500 x 100 = 50'000Kb = 50Mb. (1000Kb oder 1024Kb mal aussen vor gelassen).
Wenn während dem Timeout (Standardmässig 20 Minuten) nochmals 50 Benutzer hinzukommen, beläuft sich die Menge des benutzen Arbeitsspeicher schon auf 75Mb.
Wenn die Session-Daten im Arbeitsspeicher des Servers gehalten werden, nennt sich der Modus "InProc" (In Process), es gibt auch die Möglichkeit einen StateServer, SqlServer oder eine eigene Implementation zu verwenden um die Session-Daten auch über die Lebenszeit der Applikation zu behalten.
Cookie
Im Gegensatz zum SessionState bleiben Cookies bis zu einem gesetzten Ablaufdatum bestehen und die Daten werden auf dem Client und nicht auf dem Server gespeichert.
Das ist nütztlich um eine Funktion àla "Daten merken?" zu implementieren.
Der SessionState (temporäre Cookies) und Cookies schliessen sich also nicht nicht gegenseitig aus, sondern ergänzen sich.
So kann dieselbe Funktionalität mit dem SessionState gelöst werden und Cookies kommen dann zum Spiel, wenn die Einstellungen / Login dauerhaft, auch über eine Browsersitzung / Timout hinaus genutzt werden möchte.
Datenbank
Auch in Zusammenarbeit mit dem SessionState oder Cookies kann eine Datenbank benutzt werden, um einen Status abzuspeichern.
Der SessionState / Cookies sorgen für die Identifizierung des Benutzers und die Datenbank fungiert als Speicher.
Diese beiden Systeme (bspw. Cookie und Datenbank) assoziieren sich jeweils mit einer eindeutigen ID, sodass ein Status wiederhergestellt werden kann.
Cache
Mithilfe des Caches können Daten (Bspw. von aufwändigen Anforderungen wie die eines WebRequests oder einer langsamen Datenbankabfrage) zwischengespeichert werden, um die Anwendung zu beschleunigen.
In ASP.NET ist ausserdem das Feature "Output Cache" eingebaut, dass die aktuelle Ausgabe einer Anforderung (Bsw. einer ASP.NET Seite) zwischengespeichert werden kann.
Diese Zwischenspeicherung gilt dann (Wie auch beim normalen Cache) solange bis eine Abhängigkeit (CacheDependency) nicht mehr gültig ist.
Das kann eine Zeitdauer sein, eine Änderung einer lokalen Datei - eines Verzeichnisses oder aber etwas völlig anders (VaryByCustom oder eine eigene Abhängigkeit).
So kann bspw. für angemeldete Benutzer jeweils die Seite im Cache mit sensiblen Daten zurückgegeben werden, und bei Gästen diese ohne die sensiblen Daten, aber genauso aus dem Cache.
Ich habe den Cache hier reingenommen, da ich ihn auch für ein sehr wichtiges Mittel halte, es geht hier nicht wirklich um den Status von Client / Server sondern um die Art, Daten zwischenzuspeichern.
Application Items oder statische Variabeln
Applikationsweit _für alle Benutzer gleich_ (Siehe: Statische Variablen in ASP.NET) können Daten in der Applikations-Items-Auflistung oder - läuft im gleichen Kontext - als statische Variablen gehalten werden.
Hier ist jedoch Vorsicht geboten und die Daten gehen nach einem Applikations-Neustart wieder verloren.
Auch wird hier der Arbeitsspeicher des Servers als Medium benutzt, daher sollte auch mit der Menge der Daten sparsam umgegangen werden. (Wink an Jürgen ;-)
Andere persistente Medien (Harddisk, Textdatei, ...)
Genau so wie bei der Datenbank beschrieben, können auch andere persistente Medien als Status-Speicher benutzt weren.
Seien das jetzt Textdateien, XML-Dateien, CSV-Dateien, ....
ViewState
Das ViewState-Feature das mit ASP.NET eingeführt wurde, ist sowohl alt als auch neu.
ASP.NET benutzt die Tatsache, das viele Aufrufe in ASP.NET standardmässig per POST an den Server gesendet werden,
um aktuelle Statusinformationen in einem Html-Hidden-Field zu speichern und bei der nächsten Anforderung wieder zu lesen.
Dabei lassen sich zwei Kategorien unterscheiden: Der ControlState und der ViewState.
Der Mechanismus ist der selbe, jedoch wird der ControlState nur von WebControls benutzt und kann von einem Seitenentwickler nicht deaktiviert werden.
Der ViewState hingegen wird von ASP.NET selber auf Seitenebene genutzt und kann auch von einem Entwickler auf Seite- sowie Controlebene eingesetzt werden.
Für den View- sowie den ControlState wird jeweils ein seperates HiddenField von ASP.NET generiert und verwendet.
Das war in einer CTP so, Zitat von Jens (Danke für deinen durchaus konstruktiven Kommentar!):
Es gab mal die Variante mit "__CONTROLSTATE" in einer CTP-Version wurd aber in der Finalen Version so nicht realisiert, da dadurch Performance-Einbußen zustande kamen.
Beispielanwendung:
ViewState["key"] = "value";
Mit dieser Zuweisung erfolgt serverseitig eine Speicherung als Schlüssel / Wert-Paar (Key / Value-Pair).
Alle Zuweisungen werden von ASP.NET zu einem String serialisiert und vor dem Zurücksenden des Outputs an den Client in einem versteckten Formularfeld gespeichert.
Bei einer erneuten Anforderng per POST liest ASP.NET die Werte wieder in das Objektmodell und macht sie durch den Entwickler und die Objekte die selber agieren, abruf- und zuweisbar.
Einfach gesagt: Mit Hilfe des ViewState-Mechanismus lassen sich Daten (Besser Stati) über einen PostBack am Leben erhalten.
Jedoch funktioniert das nur solange bis die nächste Anforderung nicht mehr per POST kommt, sondern bspw. per GET.
Bei einer GET-Anforderung: Also beispielsweise einen Klick auf ein Hyperlink, ein serverseitiger Response.Redirect oder einem einfachen Refresh der Seite im Browser (Ohne das mitsenden allfälliger Formulardaten) sind alle Daten im ViewState verloren und auf den Nullzustand zurückgesetzt.
Folgendes zeig dies auf:
POST -> POST -> POST -> POST (Status bleibt die ganze Zeit erhalten)
POST -> POST -> POST -> GET -> POST (Status ist ab der ersten GET-Abfrage zurückgesetzt)
Ich hoffe dass diese Artikel ein wenig Licht ins Dunkle bringen konnte und das Verständnis zu den vorhanden Möglichkeiten stärken.
Bearbeitung / Korrekturen:
15.09.08 - Absatz über den View- und ControlState hinzugefügt (Danke an Golo)
17.09.08 - Hinweis über den ControlState korrigiert (Danke an Jens)