Einführung
In einer zustandslosen Umgebung wie einer Webanwendung hat das Verständnis des Konzepts des Sitzungsstatus keine wirkliche Bedeutung. Dennoch ist eine effektive Zustandsverwaltung für die meisten Webanwendungen ein Muss. Microsoft ASP.NET sowie viele andere serverseitige Programmierumgebungen bieten eine Abstraktionsschicht, die es Anwendungen ermöglicht, persistente Daten pro Benutzer und pro Anwendung zu speichern.
Es ist wichtig zu beachten, dass der Sitzungsstatus einer Webanwendung die Daten sind, die die Anwendung zwischenspeichert und über verschiedene Anforderungen hinweg abruft. Eine Sitzung stellt alle vom Benutzer gesendeten Anfragen dar, während er mit der Site verbunden ist, und der Sitzungsstatus ist die Sammlung persistenter Daten, die vom Benutzer während der Sitzung generiert und verbraucht werden. Der Status jeder Sitzung ist unabhängig voneinander und erlischt, wenn die Benutzersitzung endet.
Der Sitzungsstatus hat keine Entsprechung zu den logischen Einheiten, aus denen das HTTP-Protokoll und die HTTP-Spezifikation bestehen. Sitzungen sind eine Abstraktionsschicht, die von serverseitigen Entwicklungsumgebungen wie herkömmlichem ASP und ASP.NET erstellt wird. Die Art und Weise, wie ASP.NET den Sitzungsstatus anzeigt und wie der Sitzungsstatus intern implementiert wird, hängt von der Infrastruktur der Plattform ab. Daher implementieren herkömmliches ASP und ASP.NET den Sitzungsstatus auf völlig unterschiedliche Weise, und in der nächsten Version von ASP.NET werden weitere Verbesserungen und Erweiterungen erwartet.
In diesem Artikel wird erläutert, wie der Sitzungsstatus in ASP.NET 1.1 implementiert und die Sitzungsstatusverwaltung in verwalteten Webanwendungen optimiert wird.
Übersicht über den ASP.NET-Sitzungsstatus
Der Sitzungsstatus ist nicht Teil der HTTP-Infrastruktur. Das heißt, es sollte eine Strukturkomponente geben, die den Sitzungsstatus mit jeder eingehenden Anfrage verknüpft. Die Laufzeitumgebung (herkömmliches ASP oder ASP.NET) kann Schlüsselwörter wie „Session“ akzeptieren und damit den auf dem Server gespeicherten Datenblock angeben. Um Aufrufe an ein Sitzungsobjekt erfolgreich aufzulösen, muss die Laufzeitumgebung den Sitzungsstatus zum Aufrufkontext der verarbeiteten Anforderung hinzufügen. Wie dies geschieht, variiert je nach Plattform, ist jedoch für zustandsbehaftete Webanwendungen von grundlegender Bedeutung.
In herkömmlichem ASP wird der Sitzungsstatus als Free-Thread-COM-Objekte implementiert, die in der asp.dll-Bibliothek enthalten sind. (Sind Sie neugierig? Die CLSID dieses Objekts lautet tatsächlich D97A6DA0-A865-11cf-83AF-00A0C90C2BD8.) Dieses Objekt speichert Daten, die als Sammlung von Name/Wert-Paaren organisiert sind. Der Platzhalter „Name“ stellt den Schlüssel dar, der zum Abrufen der Informationen verwendet wird, während der Platzhalter „Wert“ darstellt, was im Sitzungsstatus gespeichert ist. Name/Wert-Paare werden nach Sitzungs-ID gruppiert, sodass jeder Benutzer nur die von ihm erstellten Name/Wert-Paare sieht.
In ASP.NET ist die Programmierschnittstelle für den Sitzungsstatus fast dieselbe wie in herkömmlichem ASP. Ihre grundlegenden Implementierungen sind jedoch völlig unterschiedlich. Ersteres ist flexibler, skalierbarer und verfügt über stärkere Programmierfähigkeiten als Letzteres. Bevor wir uns mit dem ASP.NET-Sitzungsstatus befassen, werfen wir einen kurzen Blick auf einige der strukturellen Funktionen der ASP.NET-Sitzungsinfrastruktur.
In ASP.NET wird jede eingehende HTTP-Anfrage über das HTTP-Modul weitergeleitet. Jedes Modul kann die große Menge an Informationen, die die Anfrage enthält, filtern und ändern. Die jeder Anforderung zugeordneten Informationen werden als „Aufrufkontext“ bezeichnet, der in der Programmierung durch das HttpContext-Objekt dargestellt wird. Wir sollten uns den Anforderungskontext nicht als einen weiteren Container mit Statusinformationen vorstellen, obwohl die von ihm bereitgestellte Items-Sammlung nur ein Datencontainer ist. Das HttpContext-Objekt unterscheidet sich von allen anderen Statusobjekten (z. B. Sitzung, Anwendung und Cache) dadurch, dass es eine begrenzte Lebensdauer hat, die über die für die Bearbeitung der Anforderung erforderliche Zeit hinausgeht. Wenn eine Anfrage eine Reihe registrierter HTTP-Module durchläuft, enthält ihr HttpContext-Objekt einen Verweis auf das Statusobjekt. Wenn die Anfrage schließlich verarbeitet werden kann, wird der zugehörige Aufrufkontext an die spezifische Sitzung (Session) und globale Statusobjekte (Anwendung und Cache) gebunden.
Das HTTP-Modul, das für die Festlegung des Sitzungsstatus jedes Benutzers verantwortlich ist, ist SessionStateModule. Die Struktur dieses Moduls basiert auf der IHttpModule-Schnittstelle, die eine große Anzahl sitzungsstatusbezogener Dienste für ASP.NET-Anwendungen bereitstellt. Beinhaltet das Generieren von Sitzungs-IDs, die Sitzungsverwaltung ohne Cookies, das Abrufen von Sitzungsdaten von externen Statusanbietern und das Binden von Daten an den Aufrufkontext der Anfrage.
Das HTTP-Modul speichert keine Sitzungsdaten intern. Der Sitzungsstatus wird immer in einer externen Komponente namens „Statusanbieter“ gespeichert. Der Statusanbieter kapselt die Sitzungsstatusdaten vollständig und kommuniziert mit anderen Teilen über die Methoden der IStateClientManager-Schnittstelle. Das Sitzungsstatus-HTTP-Modul ruft Methoden auf dieser Schnittstelle auf, um den Sitzungsstatus zu lesen und zu speichern. ASP.NET 1.1 unterstützt drei verschiedene Statusanbieter, wie in Tabelle 1 gezeigt.
Tabelle 1:
Beschreibung
des Status des Client-Anbieters
InProc-Sitzungswerte bleiben aktive Objekte im Speicher des ASP.NET-Arbeitsprozesses (aspnet_wp.exe oder w3wp.exe in Microsoft® Windows Server® 2003). Dies ist die Standardoption.
StateServer-Sitzungswerte werden serialisiert und in einem separaten Prozess (aspnet_state.exe) im Speicher gespeichert. Der Prozess kann auch auf anderen Computern ausgeführt werden.
SQLServer-Sitzungswerte werden serialisiert und in Microsoft® SQL Server®-Tabellen gespeichert. Instanzen von SQL Server können lokal oder remote ausgeführt werden.
Das Sitzungsstatus-HTTP-Modul liest den aktuell ausgewählten Statusanbieter aus dem Abschnitt <sessionState> der Datei web.config.
<sessionState mode="InProc | StateServer | SQLServer />;
Abhängig vom Wert des Modusattributs wird der Sitzungsstatus über unterschiedliche Schritte von verschiedenen Prozessen abgerufen und in diesen gespeichert. Standardmäßig wird der Sitzungsstatus in lokal gespeichert In besonderen Fällen wird er in einem dedizierten Slot des ASP.NET-Cache-Objekts gespeichert (nicht programmgesteuert zugänglich). Der Sitzungsstatus kann auch extern gespeichert werden, selbst in einem Remote-Prozess (z. B. in einem Windows). NT-Dienst mit dem Namen aspnet_state.exe. Die dritte Option besteht darin, den Sitzungsstatus in einer dedizierten Datenbanktabelle zu speichern, die von SQL Server 2000 verwaltet wird.
Das HTTP-Modul deserialisiert den Sitzungswert zu Beginn der Anforderung und macht sie zu Wörterbuchobjekten (eigentlich Objekte vom Typ HttpSessionState) werden dann programmgesteuert über die von den Klassen bereitgestellten Session-Eigenschaften (z. B. HttpContext und Page) aufgerufen. Die Bindung bleibt bestehen, bis die Anforderung erfolgreich abgeschlossen wird, werden alle Statuswerte zurückserialisiert
Abbildung 1 zeigt die Kommunikation zwischen der angeforderten ASP.NET-Seite und den Sitzungswerten. Der von jeder Seite verwendeteCode
bezieht sich auf die Programmiermethode das gleiche wie beim herkömmlichen ASP.
Abbildung 1: Sitzungsstatusarchitektur in ASP.NET 1.1
Der physische Wert des Sitzungsstatus ist für die zum Abschließen der Anforderung erforderliche Zeit gesperrt. Diese Sperre wird intern vom HTTP-Modul verwaltet und dient zur Synchronisierung des Zugriffs mit dem Sitzungsstatus.
Das Sitzungsstatusmodul instanziiert den Statusanbieter der Anwendung und initialisiert ihn mit Informationen, die aus der Datei web.config gelesen werden. Als Nächstes führt jeder Anbieter seine eigenen Initialisierungsvorgänge fort. Abhängig von der Art des Anbieters variieren die Initialisierungsvorgänge stark. Beispielsweise öffnet der SQL Server-Statusmanager eine Verbindung zu einer bestimmten Datenbank, während der Out-of-Process-Manager den angegebenen TCP-Port überprüft. Andererseits speichert der InProc-Statusmanager einen Verweis auf die Rückruffunktion. Diese Aktion wird ausgeführt, wenn ein Element aus dem Cache entfernt wird, und dient zum Auslösen des Session_OnEnd-Ereignisses der Anwendung.
Synchroner Zugriff auf den Sitzungsstatus
Was passiert, wenn eine Webseite einen sehr einfachen und intuitiven Aufruf der Session-Eigenschaft durchführt? Viele Vorgänge werden im Hintergrund ausgeführt, wie im folgenden umständlichen Code gezeigt:
int siteCount = Convert.ToInt32(Session["Counter"]);
Der obige Code greift tatsächlich auf den vom HTTP-Modul erstellten Sitzungswert im lokalen Speicher zu liest Daten von einem bestimmten staatlichen Anbieter (siehe Abbildung 1). Was passiert, wenn auch andere Seiten versuchen, synchron auf den Sitzungsstatus zuzugreifen? In diesem Fall stoppt die aktuelle Anfrage möglicherweise die Verarbeitung inkonsistenter oder veralteter Daten. Um dies zu vermeiden, implementiert das Sitzungsstatusmodul einen Lese-/Schreibsperrmechanismus und einen Warteschlangenzugriff auf Statuswerte. Seiten mit Schreibberechtigungen für den Sitzungsstatus behalten die Schreibsperre für diese Sitzung, bis die Anfrage beendet wird.
Eine Seite kann eine Schreibberechtigung für den Sitzungsstatus anfordern, indem sie die Eigenschaft „EnableSessionState“ der @Page-Direktive auf „true“ setzt. (Dies ist die Standardeinstellung). Eine Seite kann jedoch auch schreibgeschützten Zugriff auf den Sitzungsstatus haben, beispielsweise wenn die Eigenschaft „EnableSessionState“ auf „ReadOnly“ festgelegt ist. In diesem Fall behält das Modul die Lesersperre für diese Sitzung bei, bis die Anforderung für diese Seite endet. Dadurch kommt es zu gleichzeitigen Lesevorgängen.
Wenn eine Seitenanforderung eine Lesesperre setzt, können andere gleichzeitige Anforderungen in derselben Sitzung den Sitzungsstatus nicht aktualisieren, aber zumindest lesen. Das heißt, wenn gerade eine schreibgeschützte Anfrage für eine Sitzung verarbeitet wird, hat die ausstehende schreibgeschützte Anfrage eine höhere Priorität als eine Anfrage, die vollen Zugriff erfordert. Wenn eine Seitenanforderung eine Schreibsperre für den Sitzungsstatus setzt, werden alle anderen Seiten blockiert, unabhängig davon, ob sie Inhalte lesen oder schreiben möchten. Wenn beispielsweise zwei Frames gleichzeitig versuchen, in die Sitzung zu schreiben, muss ein Frame warten, bis der andere fertig ist, bevor er schreiben kann.
Vergleichen von Statusanbietern
Standardmäßig speichern ASP.NET-Anwendungen den Sitzungsstatus im Speicher eines Arbeitsprozesses, insbesondere in einem dedizierten Slot des Cache-Objekts. Wenn der InProc-Modus ausgewählt ist, wird der Sitzungsstatus in Slots innerhalb des Cache-Objekts gespeichert. Dieser Slot ist als privater Slot markiert und kann nicht programmgesteuert aufgerufen werden. Mit anderen Worten: Wenn Sie alle Elemente im ASP.NET-Datencache auflisten, werden keine Objekte zurückgegeben, die dem angegebenen Sitzungsstatus ähneln. Cache-Objekte stellen zwei Arten von Slots bereit: private Slots und öffentliche Slots. Programmierer können öffentliche Slots hinzufügen und verwalten, private Slots können jedoch nur vom System verwendet werden (insbesondere im system.web-Teil definierte Klassen).
Der Status jeder aktiven Sitzung belegt einen eigenen Platz im Cache. Der Slot wird basierend auf der Sitzungs-ID benannt und sein Wert ist eine Instanz einer internen nicht deklarierten Klasse namens SessionStateItem. Der InProc-Statusanbieter ruft die Sitzungs-ID ab und ruft das entsprechende Element im Cache ab. Der Inhalt des SessionStateItem-Objekts wird dann in das HttpSessionState-Wörterbuchobjekt eingegeben und von der Anwendung über die Session-Eigenschaft abgerufen. Beachten Sie, dass es in ASP.NET 1.0 einen Fehler gibt, der die privaten Slots des Cache-Objekts programmgesteuert aufzählbar macht. Wenn Sie den folgenden Code unter ASP.NET 1.0 ausführen, können Sie die Elemente auflisten, die den Objekten entsprechen, die in jedem aktuell aktiven Sitzungsstatus enthalten sind.
foreach(DictionaryEntry-Element im Cache)
{
Response.Write(elem.Key + ": " + elem.Value.ToString());
}
Dieser Fehler wurde in ASP.NET 1.1 behoben und wenn Sie zwischengespeicherte Inhalte aufzählen, werden keine System-Slots mehr aufgelistet.
InProc ist wahrscheinlich die mit Abstand schnellste Zugriffsoption. Beachten Sie jedoch, dass der Webserver umso mehr Speicher verbraucht, je mehr Daten in einer Sitzung gespeichert werden, was möglicherweise das Risiko einer Leistungseinbuße erhöht. Wenn Sie planen, eine Out-of-Process-Lösung zu verwenden, sollten Sie die möglichen Auswirkungen der Serialisierung und Deserialisierung sorgfältig abwägen. Die Out-of-Process-Lösung verwendet einen Windows NT-Dienst (aspnet_state.exe) oder eine SQL Server-Tabelle zum Speichern von Sitzungswerten. Daher bleibt der Sitzungsstatus außerhalb des ASP.NET-Workerprozesses und es sind zusätzliche Codeebenen erforderlich, um zwischen dem Sitzungsstatus und dem tatsächlichen Speichermedium zu serialisieren und zu deserialisieren. Dies geschieht immer dann, wenn eine Anfrage bearbeitet wird, und muss dann im höchsten Maße optimiert werden.
Da die Sitzungsdaten vom externen Repository in das lokale Sitzungswörterbuch kopiert werden müssen, führt die Anforderung zu einer Leistungseinbuße zwischen 15 % (außerhalb des Prozesses) und 25 % (SQL Server). Beachten Sie, dass es sich dabei zwar nur um eine grobe Schätzung handelt, diese jedoch nahe an der minimalen Auswirkung liegen sollte und die maximale Auswirkung viel höher ausfallen wird. Tatsächlich berücksichtigt diese Schätzung nicht vollständig die Komplexität der tatsächlich im Sitzungsstatus gespeicherten Typen.
Im Out-of-Process-Storage-Szenario bleibt der Sitzungsstatus länger erhalten, wodurch die Anwendung leistungsfähiger wird, da sie vor Ausfällen von Microsoft® Internet Information Services (IIS) und ASP.NET schützt. Durch die Trennung des Sitzungsstatus von Anwendungen können Sie vorhandene Anwendungen auch einfacher auf Web Farm- und Web Garden-Architekturen erweitern. Darüber hinaus wird der Sitzungsstatus in einem externen Prozess gespeichert, wodurch das Risiko eines periodischen Datenverlusts aufgrund von Prozessschleifen im Wesentlichen ausgeschlossen wird.
Hier erfahren Sie, wie Sie Windows NT-Dienste verwenden. Wie oben erwähnt, ist der NT-Dienst ein Prozess mit dem Namen aspnet_state.exe, der sich normalerweise im Ordner C:WINNTMicrosoft.NETFrameworkv1.1.4322 befindet.
Das tatsächliche Verzeichnis hängt von der Version von Microsoft® .NET Framework ab, die Sie tatsächlich ausführen. Bevor Sie den Statusserver verwenden, sollten Sie sicherstellen, dass der Dienst auf dem lokalen oder Remotecomputer, der als Sitzungsspeichergerät verwendet wird, bereit ist und ausgeführt wird. Der Statusdienst ist Teil von ASP.NET und wird mit ASP.NET installiert, sodass Sie kein zusätzliches Installationsprogramm ausführen müssen. Standardmäßig wird der Statusdienst nicht ausgeführt und muss manuell gestartet werden. Die ASP.NET-Anwendung versucht unmittelbar nach dem Laden, eine Verbindung zum Statusserver herzustellen. Daher muss der Dienst bereit sein und ausgeführt werden, andernfalls wird eine HTTP-Ausnahme ausgelöst. Die folgende Abbildung zeigt das Eigenschaftendialogfeld für den Dienst.
Abbildung 2: Dialogfeld „Eigenschaften des ASP.NET-Statusservers“
ASP.NET-Anwendungen müssen die TCP/IP-Adresse des Computers angeben, auf dem sich der Sitzungsstatusdienst befindet. Die folgenden Einstellungen müssen in die web.config-Datei der Anwendung eingegeben werden.
<Konfiguration>;
<system.web>;
<sessionState
mode="StateServer"
stateConnectionString="tcpip=expoware:42424" />;
</system.web>;
</configuration>;
Das Attribut stateConnectionString enthält die IP-Adresse des Computers und den für den Datenaustausch verwendeten Port. Die Standard-Computeradresse ist 127.0.0.1 (localhost) und der Standard-Port ist 42424. Sie können den Computer auch namentlich angeben. Die Verwendung eines lokalen oder Remote-Computers ist für den Code völlig transparent. Beachten Sie, dass im Namen keine Nicht-ASCII-Zeichen verwendet werden dürfen und die Portnummer obligatorisch ist.
Wenn Sie prozessexternen Sitzungsspeicher verwenden, bleibt der Sitzungsstatus bestehen und steht für die zukünftige Verwendung zur Verfügung, unabhängig davon, was mit dem ASP.NET-Workerprozess passiert. Bei einer Unterbrechung des Dienstes bleiben die Daten erhalten und werden bei Wiederherstellung des Dienstes automatisch abgerufen. Wenn der Statusanbieterdienst jedoch stoppt oder ausfällt, gehen Daten verloren. Wenn Ihre Anwendung leistungsstark sein soll, verwenden Sie den SQLServer-Modus anstelle des StateServer-Modus.
<Konfiguration>;
<system.web>;
<sessionState
mode="SQLServer"
sqlConnectionString="server=127.0.0.1;uid=<Benutzer-ID>;;pwd=<Passwort>;;"
</system.web>;
</configuration>;
Sie können die Verbindungszeichenfolge über das sqlConnectionString-Attribut angeben. Beachten Sie, dass die Attributzeichenfolge die Benutzer-ID, das Kennwort und den Servernamen enthalten muss. Es darf keine Tags wie „Datenbank“ und „Anfänglicher Katalog“ enthalten, da diese Informationen standardmäßig einen festen Namen haben. Benutzer-IDs und Passwörter können durch integrierte Sicherheitseinstellungen ersetzt werden.
Wie erstelle ich eine Datenbank? ASP.NET stellt zwei Skriptpaare zum Konfigurieren der Datenbankumgebung bereit. Das erste Skriptpaar heißt InstallSqlState.sql und UninstallSqlState.sql und befindet sich im selben Ordner wie der Session State NT-Dienst. Sie erstellen eine Datenbank namens ASPState und mehrere gespeicherte Prozeduren. Die Daten werden jedoch im temporären Speicherbereich der TempDB-Datenbank von SQL Server gespeichert. Dies bedeutet, dass bei einem Neustart des SQL Server-Computers Sitzungsdaten verloren gehen.
Um diese Einschränkung zu umgehen, verwenden Sie ein zweites Skriptpaar. Das zweite Skriptpaar heißt InstallPersistSqlState.sql und UninstallPersistSqlState.sql. In diesem Fall wird die ASPState-Datenbank erstellt, die Tabellen werden jedoch in derselben Datenbank erstellt und sind ebenfalls persistent. Wenn Sie die SQL Server-Unterstützung für Sitzungen installieren, wird auch ein Job erstellt, um abgelaufene Sitzungen in der Sitzungsstatusdatenbank zu löschen. Der Job heißt ASPState_Job_DeleteExpiredSessions und wird immer ausgeführt. Bitte beachten Sie, dass der SQLServerAgent-Dienst ausgeführt werden muss, damit dieser Job ordnungsgemäß funktioniert.
Unabhängig davon, welchen Modus Sie wählen, ändert sich die Art und Weise, wie Sitzungsstatusoperationen codiert werden, nicht. Sie können jederzeit an der Session-Eigenschaft arbeiten und wie gewohnt Werte lesen und schreiben. Alle Verhaltensunterschiede werden auf einer niedrigeren Abstraktionsebene behandelt. Die Statusserialisierung ist möglicherweise der wichtigste Unterschied zwischen Sitzungsmodi.
Statusserialisierung und Deserialisierung
Bei Verwendung des In-Process-Modus werden Objekte im Sitzungsstatus als aktive Instanzen ihrer jeweiligen Klassen gespeichert. Wenn keine echte Serialisierung und Deserialisierung erfolgt, bedeutet dies, dass Sie jedes von Ihnen in der Sitzung erstellte Objekt (einschließlich nicht serialisierbarer Objekte und COM-Objekte) tatsächlich speichern können und der Zugriff darauf nicht zu teuer ist. Wenn Sie sich für einen Out-of-Process-Statusanbieter entscheiden, ist die Sache eine andere Geschichte.
In einer Out-of-Process-Architektur werden Sitzungswerte vom lokalen Speichermedium (externe AppDomain-Datenbank) in den Speicher der AppDomain kopiert, die die Anfrage verarbeitet. Um diese Aufgabe zu erfüllen, ist eine Serialisierungs-/Deserialisierungsschicht erforderlich, die einen der größten Kostenfaktoren für Out-of-Process-Statusanbieter darstellt. Die Hauptauswirkung dieser Situation auf Ihren Code besteht darin, dass nur serialisierbare Objekte im Sitzungswörterbuch gespeichert werden können.
ASP.NET verwendet zwei Methoden zum Serialisieren und Deserialisieren von Daten, abhängig von der Art der beteiligten Daten. Für Basistypen verwendet ASP.NET einen optimierten internen Serialisierer; für andere Typen, einschließlich Objekte und benutzerdefinierte Klassen, verwendet ASP.NET den .NET-Binärformatierer. Zu den Grundtypen gehören Zeichenfolgen, Datums- und Uhrzeitangaben, boolesche Werte, Bytes, Zeichen und alle numerischen Typen. Für diese Typen ist die Verwendung eines maßgeschneiderten Serialisierers schneller als die Verwendung des standardmäßigen allgemeinen .NET-Binärformatierers.
Der optimierte Serializer wird nicht öffentlich veröffentlicht oder dokumentiert. Es ist lediglich ein binäres Lese-/Schreibgerät und verwendet eine einfache, aber effektive Speicherarchitektur. Der Serialisierer verwendet die BinaryWriter-Klasse, um eine Byte-Darstellung des Typs zu schreiben, und schreibt dann eine Byte-Darstellung des Werts, der diesem Typ entspricht. Beim Lesen serialisierter Bytes extrahiert die Klasse zunächst ein Byte, erkennt den zu lesenden Datentyp und ruft dann die typspezifische ReadXxx-Methode der BinaryReader-Klasse auf.
Beachten Sie, dass die Größe boolescher und numerischer Typen bekannt ist, nicht jedoch die Größe von Zeichenfolgen. Im zugrunde liegenden Datenstrom wird der Zeichenfolge immer eine feste Länge vorangestellt (ein 7-Bit-Ganzzahlcode, der jeweils geschrieben wird), und der Leser nutzt diese Tatsache, um die richtige Größe der Zeichenfolge zu bestimmen. Der Datumswert wird gespeichert, indem nur die Gesamtzahl der Token geschrieben wird, aus denen das Datum besteht. Um die Sitzung zu serialisieren, sollte das Datum daher vom Typ Int64 sein.
Sie können die BinaryFormatter-Klasse verwenden, um Serialisierungsvorgänge für komplexere Objekte (sowie benutzerdefinierte Objekte) durchzuführen, solange die enthaltende Klasse als serialisierbar markiert ist. Alle Nicht-Basistypen werden durch dieselbe Typ-ID identifiziert und im selben Datenstrom wie die Basistypen gespeichert. Insgesamt können Serialisierungsvorgänge zu einer Leistungseinbuße von 15 bis 25 % führen. Beachten Sie jedoch, dass es sich hierbei um eine grobe Schätzung handelt, die auf der Annahme basiert, dass Basistypen verwendet werden. Je komplexer die verwendeten Typen sind, desto größer ist der Overhead.
Eine effiziente Speicherung von Sitzungsdaten ist ohne den umfassenden Einsatz primitiver Typen schwer zu implementieren. Zumindest theoretisch ist es also besser, drei Sitzungsslots zum Speichern von drei verschiedenen Zeichenfolgeneigenschaften eines Objekts zu verwenden, als das gesamte Objekt zu serialisieren. Was aber, wenn das Objekt, das Sie serialisieren möchten, 100 Eigenschaften enthält? Möchten Sie 100 Slots nutzen oder nur einen Slot? In vielen Fällen besteht ein besserer Ansatz darin, einen komplexen Typ in mehrere einfachere Typen umzuwandeln. Dieser Ansatz basiert auf Typkonvertern. Ein „Typkonverter“ ist ein einfacher Serialisierer, der die Schlüsseleigenschaften eines Typs als Sammlung von Zeichenfolgen zurückgibt. Typkonverter sind externe Klassen, die über Attribute an eine Basisklasse gebunden sind. Es ist Sache des Schreibers, zu entscheiden, welche Eigenschaften wie gespeichert werden. Typkonverter sind auch für die ViewState-Speicherung hilfreich und stellen eine effizientere Methode der Sitzungsspeicherung dar als binäre Formatierer.
Sitzungslebenszyklus
Ein wichtiger Punkt bei der ASP.NET-Sitzungsverwaltung besteht darin, dass der Lebenszyklus des Sitzungsstatusobjekts erst beginnt, wenn das erste Element zum In-Memory-Wörterbuch hinzugefügt wird. Eine ASP.NET-Sitzung gilt erst dann als gestartet, wenn der folgende Codeausschnitt ausgeführt wurde.
Session["MySlot"] = "Some data";
Das Session-Wörterbuch enthält normalerweise den Objekttyp. Um Daten rückwärts zu lesen, muss der zurückgegebene Wert in einen spezifischeren Typ konvertiert werden.
string data = (string) Session["MySlot"];
Wenn die Seite Daten in der Sitzung speichert, wird der Wert in die speziell gestaltete Wörterbuchklasse geladen, die in der HttpSessionState-Klasse enthalten ist. Der Inhalt des Wörterbuchs wird in den Statusanbieter geladen, wenn die aktuell verarbeitete Anfrage abgeschlossen ist. Wenn der Sitzungsstatus leer ist, weil die Daten nicht programmgesteuert in das Wörterbuch eingefügt wurden, werden die Daten nicht auf dem Speichermedium serialisiert und, was noch wichtiger ist, nicht in ASP.NET Cache, SQL Server oder NT State Services Create bereitgestellt Ein Slot, um die aktuelle Sitzung zu verfolgen. Dies geschieht aus Leistungsgründen, hat jedoch erhebliche Auswirkungen auf die Handhabung von Sitzungs-IDs: Für jede Anfrage wird eine neue Sitzungs-ID generiert, bis einige Daten im Sitzungswörterbuch gespeichert sind.
Wenn der Sitzungsstatus mit einer verarbeiteten Anforderung verknüpft werden muss, ruft das HTTP-Modul die Sitzungs-ID ab (sofern es sich nicht um die initiierende Anforderung handelt) und sucht im konfigurierten Statusanbieter danach. Wenn keine Daten zurückgegeben werden, generiert das HTTP-Modul eine neue Sitzungs-ID für die Anfrage. Dies kann einfach mit der folgenden Seite getestet werden:
<%@ Page Language="C#" Trace="true" %>;
</html>;
<Körper>;
<form runat="server">;
<asp:button runat="server" text="Click" />;
</form>;
</Körper>;
</html>;
Immer wenn Sie auf die Schaltfläche klicken und zur Seite zurückkehren, wird eine neue Sitzungs-ID generiert und Tracking-Informationen aufgezeichnet.
Abbildung 3: In einer Anwendung, die keine Daten in einem Sitzungswörterbuch speichert, wird für jede Anfrage eine neue Sitzungs-ID generiert.
Was ist mit dem Session_OnStart-Ereignis? Wird das Ereignis auch bei jeder Anfrage ausgelöst? Wenn Ihre Anwendung einen Session_OnStart-Handler definiert, wird der Sitzungsstatus immer gespeichert, auch wenn der Sitzungsstatus leer ist. Daher ist die Sitzungs-ID für alle Anfragen nach der ersten Anfrage immer konstant. Verwenden Sie den Session_OnStart-Handler nur, wenn dies unbedingt erforderlich ist.
Wenn eine Sitzung abläuft oder abgebrochen wird, ändert sich ihre Sitzungs-ID beim nächsten Zugriff auf die zustandslose Anwendung nicht. Es ist so konzipiert, dass die Sitzungs-ID bis zum Ende der Browsersitzung bestehen bleibt, auch wenn der Sitzungsstatus abläuft. Das heißt, dass zur Darstellung mehrerer Sitzungen immer dieselbe Sitzungs-ID verwendet wird, solange die Browserinstanz dieselbe ist.
Das Session_OnEnd-Ereignis markiert das Ende einer Sitzung und wird verwendet, um jeglichen Bereinigungscode auszuführen, der zum Beenden der Sitzung erforderlich ist. Beachten Sie jedoch, dass dieses Ereignis nur im InProc-Modus unterstützt wird, also nur, wenn Sitzungsdaten in einem ASP.NET-Workerprozess gespeichert werden. Damit das Session_OnEnd-Ereignis ausgelöst wird, muss zunächst ein Sitzungsstatus vorhanden sein, was bedeutet, dass einige Daten im Sitzungsstatus gespeichert sein müssen und mindestens eine Anfrage abgeschlossen sein muss.
Im InProc-Modus wird dem Sitzungsstatus, der dem Cache als Elemente hinzugefügt wird, eine variable Ablaufzeitrichtlinie zugewiesen. Variabler Ablauf bedeutet, dass ein Artikel gelöscht wird, wenn er innerhalb eines bestimmten Zeitraums nicht verwendet wird. Die Ablaufzeit aller in diesem Zeitraum bearbeiteten Anfragen wird zurückgesetzt. Das Intervall des Sitzungsstatuselements wird auf das Sitzungszeitlimit festgelegt. Die zum Zurücksetzen der Ablaufzeit des Sitzungsstatus verwendete Technik ist sehr einfach und intuitiv: Das Sitzungs-HTTP-Modul liest einfach die im ASP.NET-Cache gespeicherten Sitzungsstatuselemente. Wenn die interne Struktur des ASP.NET-Cache-Objekts bekannt ist, führt das Modul Berechnungen durch, um die Ablaufzeit der Variablen zurückzusetzen. Wenn das zwischengespeicherte Element abläuft, ist die Sitzung abgelaufen.
Abgelaufene Elemente werden automatisch aus dem Cache entfernt. Das Statussitzungsmodul stellt im Rahmen der Ablaufzeitrichtlinie für dieses Projekt auch eine Rückruffunktion zum Löschen dar. Der Cache ruft automatisch die Löschfunktion auf, die dann das Session_OnEnd-Ereignis auslöst. Wenn eine Anwendung die Sitzungsverwaltung über eine Out-of-Process-Komponente durchführt, wird das Endereignis nie ausgelöst.
Sitzungen ohne Cookies
Jede aktive ASP.NET-Sitzung wird anhand einer 120-Bit-Zeichenfolge identifiziert, die nur aus den von der URL zulässigen Zeichen besteht. Die Sitzungs-ID wird mithilfe eines kryptografischen Anbieters mit Zufallszahlengenerator (Random Number Generator, RNG) generiert. Der Dienstanbieter gibt eine Folge von 15 zufällig generierten Zahlen zurück (15 Bytes x 8 Bits = 120 Bits). Das Array aus Zufallszahlen wird dann gültigen URL-Zeichen zugeordnet und als String zurückgegeben.
Die Sitzungs-ID-Zeichenfolge wird an den Browser gesendet und auf zwei Arten an die Serveranwendung zurückgegeben: mithilfe eines Cookies (genau wie bei herkömmlichem ASP) oder einer geänderten URL. Standardmäßig erstellt das Sitzungsstatusmodul ein HTTP-Cookie auf der Clientseite, es kann jedoch auch eine modifizierte URL verwendet werden, die die Sitzungs-ID-Zeichenfolge einbettet (insbesondere für Browser, die keine Cookies unterstützen). Welche Methode verwendet wird, hängt von den Konfigurationseinstellungen ab, die in der web.config-Datei der Anwendung gespeichert sind. Um Sitzungseinstellungen zu konfigurieren, können Sie den Abschnitt <sessionState> und das Cookieless-Attribut verwenden.
<sessionState cookieless="true|false" />;
Standardmäßig ist das Cookieless-Attribut „false“, was darauf hinweist, dass Cookies verwendet werden. Tatsächlich handelt es sich bei einem Cookie lediglich um eine Textdatei, die von einer Webseite auf der Festplatte des Clients abgelegt wird. In ASP.NET wird ein Cookie durch eine Instanz der HttpCookie-Klasse dargestellt. Normalerweise enthält ein Cookie einen Namen, eine Reihe von Werten und eine Ablaufzeit. Wenn das Cookieless-Attribut auf „false“ gesetzt ist, erstellt das Sitzungsstatusmodul tatsächlich ein Cookie mit dem Namen ASP.NET_SessionId und speichert darin die Sitzungs-ID. Der folgende Pseudocode zeigt den Prozess der Erstellung eines Cookies:
HttpCookie sessionCookie;
sessionCookie = new HttpCookie("ASP.NET_SessionId", sessionID);
sessionCookie.Path = „/“;
Die Ablaufzeit des Sitzungscookies ist sehr kurz und wird nach jeder erfolgreichen Anfrage aktualisiert. Das Expires-Attribut des Cookies gibt die Ablaufzeit des Cookies auf dem Client an. Wenn das Sitzungscookie nicht explizit festgelegt ist, verwendet die Expires-Eigenschaft standardmäßig DateTime.MinValue, die kleinste vom .NET Framework zugelassene Zeiteinheit.
Um Sitzungscookies zu deaktivieren, setzen Sie das Cookieless-Attribut in der Konfigurationsdatei wie folgt auf true:
<configuration>;
<system.web>;
<sessionState Cookieless="true" />;
</system.web>;
</configuration>;
Gehen Sie zu diesem Zeitpunkt davon aus, dass Sie die Seite unter der folgenden URL anfordern:
http://www.contoso.com/sample.aspx.
Der tatsächliche Inhalt, der in der Adressleiste des Browsers angezeigt wird, unterscheidet sich und enthält jetzt die Sitzungs-ID , wie folgt. Gezeigt in:
http://www.contoso.com/(5ylg0455mrvws1uz5mmaau45)/sample.aspx
Beim Instanziieren des Sitzungsstatus-HTTP-Moduls überprüft das Modul den Wert des Cookieless-Attributs. Wenn „true“, wird die Anfrage (HTTP 302) an eine geänderte virtuelle URL umgeleitet, die die Sitzungs-ID direkt vor dem Seitennamen enthält. Wenn die Anfrage erneut verarbeitet wird, wird die Sitzungs-ID in die Anfrage aufgenommen. Wenn eine Anfrage zum Starten einer neuen Sitzung gestellt wird, generiert das HTTP-Modul eine neue Sitzungs-ID und leitet die Anfrage dann um. Wenn die Anfrage zurückgesendet wird, ist die Sitzungs-ID bereits vorhanden, da Postbacks relative URLs verwenden.
Der Nachteil von Sitzungen ohne Cookies besteht darin, dass der Sitzungsstatus verloren geht, wenn eine absolute URL aufgerufen wird. Wenn Sie Cookies verwenden, können Sie die Adressleiste löschen, zu einer anderen Anwendung wechseln und dann zur vorherigen Anwendung zurückkehren und denselben Sitzungswert abrufen. Wenn Sie dies tun, während Sitzungscookies deaktiviert sind, gehen Sitzungsdaten verloren. Beispielsweise unterbricht der folgende Code die Sitzung:
<a runat="server" href="/code/page.aspx">;Click</a>;
Wenn Sie eine absolute URL verwenden müssen, wenden Sie dazu bitte einige Tricks an Ändern Sie die der URL hinzugefügte Sitzungs-ID manuell. Sie können die ApplyAppPathModifier-Methode für die HttpResponse-Klasse aufrufen.
<a runat="server"
href=<% =Response.ApplyAppPathModifier("/code/page.aspx")%>; >;Click</a>;
Die ApplyAppPathModifier-Methode verwendet eine Zeichenfolge, die die URL darstellt, und gibt die absolute URL zurück, in die die Sitzungsinformationen eingebettet sind. Diese Technik ist besonders nützlich, wenn Sie beispielsweise von einer HTTP-Seite auf eine HTTPS-Seite umleiten müssen.
Zusammenfassung
Der Sitzungsstatus wurde ursprünglich mit herkömmlichem ASP als wörterbuchbasierte API eingeführt, die es Entwicklern ermöglichte, benutzerdefinierte Daten während einer Sitzung zu speichern. In ASP.NET unterstützt der Sitzungsstatus zwei Hauptfunktionen: Speicherung und Übertragung von Sitzungs-IDs ohne Cookies sowie Anbieter, bei denen die Sitzungsdaten tatsächlich gespeichert werden. Um diese beiden neuen Funktionen zu implementieren, nutzt ASP.NET das HTTP-Modul, um die Bindung zwischen dem Sitzungsstatus und dem Kontext der verarbeiteten Anforderung zu steuern.
In herkömmlichem ASP bedeutet die Verwendung des Sitzungsstatus die Verwendung von Cookies. Dies ist in ASP.NET nicht mehr der Fall, da eine Cookieless-Architektur verwendet werden kann. Mithilfe des HTTP-Moduls kann die angeforderte URL so zerlegt werden, dass sie die Sitzungs-ID enthält, und dann umgeleitet werden. Als nächstes extrahiert das HTTP-Modul die Sitzungs-ID aus der URL und nutzt sie, um jeden gespeicherten Status abzurufen.
Der physische Zustand einer Sitzung kann an drei Orten gespeichert werden: In-Process-Speicher, Out-of-Process-Speicher und SQL Server-Tabellen. Die Daten müssen serialisiert/deserialisiert werden, bevor sie von der Anwendung verwendet werden können. Das HTTP-Modul kopiert den Sitzungswert zu Beginn der Anfrage vom Anbieter in den Speicher der Anwendung. Nach Abschluss der Anfrage wird der geänderte Status an den Anbieter zurückgegeben. Diese Datenkommunikation hat unterschiedlich starke negative Auswirkungen auf die Leistung, erhöht aber die Zuverlässigkeit und Stabilität erheblich und erleichtert die Implementierung der Unterstützung für Web Farm- und Web Garden-Architekturen.