Domanda

Di recente, mentre si lavora su un codice per un progetto ASP.NET al lavoro. Avevamo bisogno di un util di tracciamento per prendere le metriche di base sull'attività degli utenti (numero di accessi alla pagina, ecc.) Che li seguiremmo in Session , quindi salva i dati su DB tramite Session_End in Global.asax .

Ho iniziato a smanettare, il codice iniziale ha funzionato bene, aggiornando il DB ad ogni caricamento della pagina. Volevo rimuovere questo hit DB su ogni richiesta e basarmi su Session_End per archiviare tutti i dati.

Tutto il codice di monitoraggio è incapsulato nella classe Tracker , incluse le proprietà che essenzialmente racchiudono le variabili Session.

Il problema è che quando ho eseguito Tracker.Log () nel metodo Session_End , il HttpContext.Current.Session nel codice Tracker era non riuscito con un NullReferenceException . Ora, questo ha senso dal HttpContext si riferisce sempre alla richiesta corrente e, naturalmente, in Session_End , non vi è alcuna richiesta.

So che Global.asax ha una proprietà Session che restituisce un HttpSessionState che in realtà sembra funzionare bene (ho finito per iniettarlo al tracker) ..

Ma sono curioso, come diavolo posso ottenere lo stesso riferimento all'oggetto HttpSessionState utilizzato da Global.asax da esterno di Global.asax?

Grazie in anticipo ragazzi, apprezzo l'input. :)

È stato utile?

Soluzione

Global.asax implementa HttpApplication - che è ciò con cui stai parlando quando chiami questo dall'interno.

La documentazione MSDN per HttpApplication contiene dettagli su come puoi ottenerlo in un HttpHandler per esempio, e quindi ottenere l'accesso alle varie proprietà su di esso.

TUTTAVIA

La tua applicazione può creare più istanze di HttpApplication per gestire le richieste parallele e queste istanze possono essere riutilizzate, quindi raccoglierle in qualche modo non garantirà che hai quella giusta.

Anch'io aggiungerei anche una nota di cautela: se la tua applicazione si arresta in modo anomalo, non vi è alcuna garanzia che verrà chiamato session_end e avrai perso tutti i dati in tutte le sessioni, chiaramente non è una buona cosa.

Sono d'accordo sul fatto che accedere a ogni pagina non è probabilmente una grande idea, ma forse una casa a metà strada con un po 'di registrazione asincrona in corso - si sparano i dettagli a una classe di registrazione, che ogni tanto registra i dettagli che si stanno cercando - ancora non solido al 100% se l'app si blocca, ma è meno probabile che tu perda tutto.

Altri suggerimenti

Per rispondere meglio alla domanda originale:

Sfondo

Ogni singola richiesta di pagina fa girare un nuovo oggetto Session e poi lo gonfia dal tuo archivio di sessioni. Per fare ciò, utilizza il cookie fornito dal client o un costrutto di percorso speciale (per sessioni senza cucina). Con questo identificatore di sessione, consulta l'archivio sessioni e deserializza (ecco perché tutti i provider tranne InProc devono essere serializzabili) il nuovo oggetto sessione.

Nel caso del provider InProc, ti passa semplicemente il riferimento memorizzato nel HttpCache , digitato dall'identificatore di sessione. Ecco perché il provider InProc abbandona lo stato della sessione quando AppDomain viene riciclato (e anche perché più server Web non possono condividere lo stato della sessione InProc .

Questo oggetto appena creato e gonfiato è bloccato nella raccolta Context.Items in modo che sia disponibile per la durata della richiesta.

Qualsiasi modifica apportata all'oggetto Session viene quindi mantenuta al termine della richiesta all'archivio sessioni serializzando (o nel caso di InProc, la voce HttpCache è aggiornato).

Poiché Session_End si attiva senza una richiesta corrente in tempo reale, l'oggetto Session viene lanciato ex-nilo, senza informazioni disponibili. Se si utilizza lo stato della sessione InProc, la scadenza di HttpCache attiva un evento di richiamata nell'evento Session_End , quindi la voce della sessione è disponibile, ma rimane comunque una copia dell'ultima memorizzato in HttpContext.Cache . Questo valore viene archiviato nella proprietà HttpApplication.Session mediante un metodo interno (chiamato ProcessSpecialRequest ) dove è quindi disponibile. In tutti gli altri casi, proviene internamente dal valore HttpContext.Current.Session .

La tua risposta

Poiché Session_End si attiva sempre in un contesto null, è consigliabile utilizzare SEMPRE this.Session in quell'evento e passare l'oggetto HttpSessionState al codice di traccia. In tutti gli altri contesti, è perfettamente possibile recuperare da HttpContext.Current.Session e quindi passare al codice di traccia. NON , tuttavia, consenti al codice di traccia di raggiungere il contesto della sessione.

La mia risposta

Non utilizzare Session_End a meno che non si sappia che l'archivio sessioni in uso supporta Session_End , che esegue se restituisce true da SetItemExpireCallback . L'unico negozio pronto che lo fa è l'archivio InProcSessionState . È possibile scrivere un archivio di sessioni che lo fa ma la domanda su chi elaborerà Session_End è in qualche modo ambigua se ci sono più server.

Penso che tu abbia già risposto alla tua domanda: di solito le proprietà Session in Global.asax e HttpContext.Current.Session sono le stesse (se c'è una richiesta corrente). Ma nel caso di un timeout della sessione, non vi è alcuna richiesta attiva e pertanto non è possibile utilizzare HttpContext.Current.

Se si desidera accedere alla sessione dal metodo chiamato da Session_End, passarlo come parametro. Crea una versione sovraccarica del metodo Log (), che accetta un HttpSessionState come parametro, quindi chiama Tracker.Log (this.Session) dal gestore eventi Session_End.

A proposito: sai che non puoi fare affidamento sull'evento di fine sessione in ogni caso? Funzionerà solo finché avrai lo stato della sessione in corso. Quando si utilizza SQL Server o StateServer per gestire lo stato della sessione, l'evento di fine della sessione non verrà generato.

L'evento Session_End viene generato solo quando modalità sessionstate è impostato su InProc in Web.config file. Se la modalità sessione è impostata su StateServer o SQLServer , l'evento non viene generato.

usa Sessione [" SessionItemKey "] per ottenere il valore della sessione.

Ok, sono nello stesso problema per tenere traccia dell'attività della sessione. Invece di utilizzare l'evento session_end, ho implementato l'interfaccia IDisposable e il distruttore nella mia classe sessiontracker. Ho modificato il metodo Dispose () per salvare l'attività della sessione su DB. Ho invocato il metodo obj.Dispose () quando un utente fa clic sul pulsante di disconnessione. Se l'utente ha chiuso il browser per errore, GC chiamerà il distruttore mentre pulisce gli oggetti (non immediatamente ma sicuramente chiamerà questo metodo dopo qualche tempo). Il metodo distruttore esegue internamente lo stesso metodo Dispose () per salvare le attività della sessione in DB.

-Shan

Sessione è disponibile nel file Global.asax, durante l'evento Session_Start. Forse aspettare fino a questo punto per fare cose?

Ricorda che Session_End viene eseguito quando la sessione scade senza attività. Il browser non origina quell'evento (perché è inattivo), quindi l'unica volta che otterrai effettivamente l'evento è quando usi il provider InProc. In OGNI ALTRO fornitore, questo evento non si attiva mai.

Morale? Non utilizzare Session_End.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top