„HttpContext.Current.Session“ vs Global.asax „this.session“
-
19-08-2019 - |
Frage
Vor kurzem, während für eine ASP.NET-Projekt bei der Arbeit an einigen Code zu arbeiten. Wir brauchten util eine Tracking-Basismetriken auf Benutzeraktivität zu nehmen (Seite treffen usw. zählen) wir sie in Session
, dann die Daten an die DB speichern über Session_End
in Global.asax
.
ich weg begann Hacker, der anfängliche Code hat gut funktioniert, auf jeder Seite zu laden, die DB zu aktualisieren. Ich wollte, obwohl diese DB treffen auf jede Anfrage entfernen und verlassen sich nur auf Session_End
alle Daten zu speichern.
Alle Tracking-Code wird in der Tracker
Klasse gekapselt, einschließlich Eigenschaften, die im Wesentlichen die Session-Variablen wickeln.
Das Problem ist, dass, wenn ich Tracker.Log()
im Session_End
Methode ausgeführt, die HttpContext.Current.Session
im Tracker-Code wurde mit einem NullReferenceException
. Nun ist dies sinnvoll, da HttpContext
immer auf die bezieht Strom Anfrage und natürlich in Session_End
, gibt es keine Anfrage.
Ich weiß, dass Global.asax
eine Session
Eigenschaft hat, die eine HttpSessionState
zurückgibt, scheint tatsächlich zu funktionieren (ich landete sie in an den Tracker Injektion) ..
Aber ich bin neugierig, wie zum Teufel kann ich den gleichen Verweis auf das HttpSessionState
Objekt erhalten, indem Global.asax
von verwendet außerhalb von Global.asax
?
Vielen Dank im Voraus Jungs, ich schätze die Eingabe. :)
Lösung
Global.asax implementiert Httpapplication -. Das ist, was Sie sprechen, wenn Sie anrufen dieses aus it
Die MSDN-Dokumentation für Httpapplication hat Details zu wie können Sie halten es in einem Httphandler zum Beispiel, und dann Zugriff auf die verschiedenen Eigenschaften auf es.
JEDOCH
Ihre Anwendung kann mehrere Instanzen von Httpapplication erstellen parallel Anfragen zu bearbeiten, und diese Fälle wiederverwendet werden können, so einfach es irgendwie Abholung wird nicht zu garantieren, dass Sie die richtigen haben.
Auch ich würde auch eine Notiz von Vorsicht hinzufügen - wenn Ihre Anwendung abstürzt, gibt es keine Garantie, die aufgerufen werden Session_End wird, und Sie werden alle Daten in allen Sitzungen verloren haben, eindeutig nicht eine gute Sache.
Ich bin damit einverstanden, dass auf jeder Seite der Anmeldung ist wahrscheinlich keine gute Idee, aber vielleicht ein halbes Haus mit einigen asynchronen Protokollierung geschieht - Sie Details Feuer auf eine Logging-Klasse aus, dass jeder von Zeit zu Zeit protokolliert die Details, die Sie nach sind - noch wenn die App abstürzt nicht zu 100% fest, aber Sie sind weniger wahrscheinlich, alles zu verlieren.
Andere Tipps
die ursprüngliche Frage zu beantworten, besser:
Hintergrund
Jede einzelne Seite Anfrage spinnt ein neues Session
Objekt und dann bläht es aus Ihrer Sitzung zu speichern. Dazu verwendet er die vom Kunden zur Verfügung gestellt Cookie oder eine speziellen Pfad construct (für Sitzungen ohne Cookies). Mit diesem Sitzungs-ID, konsultiert er die Sitzung zu speichern und deserialisiert (aus diesem Grunde alle Anbieter aber InProc sein müssen Serializable) Objekt der neue Sitzung.
Im Falle des InProc Anbieter, nur Hände Sie den Verweis in der HttpCache
gespeichert durch die Sitzungs-ID eingegeben. Diese ist, warum der InProc Anbieter Sitzungszustand fällt, wenn die AppDomain
zurückgeführt wird (und warum auch mehrere Web-Server nicht InProc Sitzungsstatus teilen .
Das neu erstellt und aufgeblasen Objekt wird in der Context.Items
Sammlung stecken, so dass sie für die Dauer der Anforderung verfügbar sind.
Alle Änderungen an das Session
Objekt vornehmen, werden dann am Ende des Antrags an den Sitzungsspeicher beharrte durch Serialisierung (oder im Fall von InProc, der HttpCache
Eintrag aktualisiert wird).
Da Session_End
Brände ohne aktuelle Anforderung in-fly, wird das Objekt Session
versponnen Ab-Werk-nilo, ohne Informationen verfügbar. Wenn InProc Sitzungszustand verwendet wird, löst sich der Ablauf der HttpCache
eine Callback-Ereignis in Ihrem Session_End
Ereignis, so dass der Sitzungseintrag ist vorhanden, aber es ist immer noch eine Kopie dessen, was zuletzt in der HttpContext.Cache
gespeichert. Dieser Wert wird gespeichert gegen die HttpApplication.Session
Eigenschaft durch ein internes Verfahren (genannt ProcessSpecialRequest
), wo es dann zur Verfügung. In allen anderen Fällen kommt es intern vom HttpContext.Current.Session
Wert.
Ihre Antwort
Da die Session_End immer feuert gegen einen Null-Kontext, sollten Sie immer this.session in diesem Fall und übergeben Sie die Httpsessionstate zu Ihrem Tracing-Code Objekt nach unten. In allen anderen Bereichen, ist es völlig in Ordnung, von HttpContext.Current.Session
zu holen und dann den Verfolgungscode passiert in. NICHT , lassen jedoch der Verfolgungscode für den Sitzungskontext reicht.
Meine Antwort
Verwenden Sie Session_End
nicht, wenn Sie wissen, dass die Sitzung speichern Sie unterstützt Session_End
verwenden, die es funktioniert , wenn es true
von SetItemExpireCallback
zurückgibt. Das einzige in-the-Box-Geschäft, das tut, ist der InProcSessionState
Speicher. Es ist möglich, einen Session-Speicher zu schreiben, das tut aber die Frage, wer Art mehrdeutig die Session_End
ist, wird verarbeitet, wenn es mehrere Server.
Ich glaube, Sie bereits Ihre eigene Frage beantwortet: in der Regel der Session-Immobilie in Global.asax und HttpContext.Current.Session gleich ist (wenn es eine aktuelle Anforderung ist). Aber im Fall eines Session-Timeout, gibt es keine aktive Anfrage und daher können Sie nicht HttpContext.Current verwenden.
Wenn Sie die Sitzung aus dem von Session_End aufgerufen zugreifen wollen, dann geben sie als Parameter. Erstellen Sie eine überladene Version der Log () -Methode, die ein Httpsessionstate als Parameter annimmt, dann rufen Tracker.Log (this.session) von der Session_End Ereignishandler.
BTW: Sie sind sich bewusst, dass Sie nicht auf der Sitzung Ende Ereignis in jedem Fall verlassen können? Es wird nur so lange arbeiten, wie Sie den Sitzungsstatus in-Prozess haben. Wenn SQL Server oder State mit dem Sitzungsstatus Räude, wird die Sitzung-End-Ereignis nicht ausgelöst.
Das Session_End
Ereignis wird nur ausgelöst, wenn der sessionstate mode
gesetzt in der InProc
Datei Web.config
. Wenn Sitzungsmodus StateServer
oder SQLServer
gesetzt ist, wird das Ereignis nicht ausgelöst.
Verwendung Session["SessionItemKey"]
den Sitzungswert zu erhalten.
Okay, ich bin in dem gleichen Problem die Sitzungsaktivität zu verfolgen. Statt Session_End Ereignis zu verwenden, habe ich die IDisposable-Schnittstelle und destructor meine sessiontracker Klasse implementiert. Ich habe die Methode Dispose () modifiziert, um die Sitzungsaktivität an die DB zu speichern. I aufgerufen, um das Verfahren obj.Dispose (), wenn ein Benutzer die Logout Schaltfläche klickt. Wenn der Benutzer den Browser versehentlich geschlossen, dann wird GC den Destruktor aufrufen, während die Objekte Reinigung (nicht sofort, aber sicher wird es diese Methode, nach einiger Zeit nennen). Die Destruktormethode intern führen Sie die gleiche Methode Dispose () die Sitzungsaktivitäten in DB zu speichern.
-Shan
Session ist in der Datei Global.asax, während der Session_Start Veranstaltung. Vielleicht bis dahin warten, Dinge zu tun?
Beachten Sie, dass Session_End läuft, wenn die Sitzung abläuft, ohne Aktivität. Der Browser stammt nicht das Ereignis (weil es inaktiv ist), so dass die einzige Zeit, die Sie das Ereignis tatsächlich erhalten wird, wenn der InProc Anbieter verwendet. In jedem anderen Anbieter, wird dieses Ereignis nie ausgelöst.
Moral? Nicht Session_End verwenden.