asp.net session session-state global-asax

asp.net - "HttpContext.Current.Session" vs Global.asax "this.Session"



session-state global-asax (7)

Recientemente, mientras trabajaba en algún código para un proyecto ASP.NET en el trabajo. Necesitábamos una herramienta de seguimiento para tomar métricas básicas sobre la actividad del usuario (conteo de aciertos de página, etc.), los Session_End en la Session , luego Session_End los datos en DB a través de Session_End en Global.asax .

Empecé a piratear, el código inicial funcionaba bien, actualizando el DB en cada carga de página. Sin embargo, quería eliminar este golpe de DB en cada solicitud y solo Session_End en Session_End para almacenar todos los datos.

Todo el código de seguimiento está encapsulado en la clase Tracker , incluidas las propiedades que envuelven esencialmente las variables de sesión.

El problema es que cuando Tracker.Log() en el método Session_End , la HttpContext.Current.Session en el código del Tracker estaba fallando con una NullReferenceException . Ahora, esto tiene sentido ya que HttpContext siempre se relaciona con la solicitud actual , y por supuesto en Session_End , no hay solicitud.

Sé que Global.asax tiene una propiedad Session que devuelve un HttpSessionState que en realidad parece funcionar bien (terminé inyectándolo en el rastreador) ..

Pero tengo curiosidad, ¿cómo demonios puedo obtener la misma referencia al objeto HttpSessionState utilizado por Global.asax desde fuera de Global.asax ?

Gracias de antemano chicos, agradezco la entrada. :)


Creo que ya respondió su propia pregunta: por lo general, la propiedad Session en Global.asax y HttpContext.Current.Session son las mismas (si hay una solicitud actual). Pero en el caso de un tiempo de espera de sesión, no hay una solicitud activa y, por lo tanto, no puede usar HttpContext.Current.

Si desea acceder a la sesión desde el método llamado por Session_End, páselo como parámetro. Cree una versión sobrecargada del método Log (), que toma un HttpSessionState como parámetro, luego llame a Tracker.Log (this.Session) desde el controlador de eventos Session_End.

Por cierto: ¿sabe usted que no puede confiar en el evento final de la sesión en ningún caso? Solo funcionará mientras tenga el estado de la sesión en proceso. Al usar SQL Server o StateServer para manejar el estado de la sesión, el evento de final de sesión no se activará.


Global.asax implementa HttpApplication, que es con lo que está hablando cuando llama a esto desde dentro.

La documentación de MSDN para HttpApplication contiene detalles sobre cómo puede obtenerla en un HttpHandler, por ejemplo, y luego obtener acceso a las diversas propiedades que contiene.

SIN EMBARGO

Su aplicación puede crear varias instancias de HttpApplication para manejar solicitudes paralelas, y estas instancias se pueden reutilizar, por lo que simplemente retomarlas de alguna manera no va a garantizar que tenga la correcta.

Yo también agregaría una nota de precaución: si su aplicación falla, no hay garantía de que se llame a session_end, y habrá perdido todos los datos en todas las sesiones, claramente no es algo bueno.

Estoy de acuerdo en que iniciar sesión en todas las páginas probablemente no sea una buena idea, pero tal vez sea un punto intermedio con algunas actividades de registro asíncronas. Describe los detalles en una clase de registro, que de vez en cuando registra los detalles que está buscando. Todavía no es 100% sólido si la aplicación falla, pero es menos probable que pierda todo.


Recuerde que Session_End se ejecuta cuando la sesión termina sin actividad. El navegador no origina ese evento (porque está inactivo), por lo que la única vez que obtendrá el evento es cuando usa el proveedor de InProc. En CADA OTRO proveedor, este evento nunca se disparará.

¿Moral? No use Session_End.


De acuerdo, estoy en el mismo problema para rastrear la actividad de la sesión. En lugar de usar el evento session_end, he implementado la interfaz IDisposable y el destructor en mi clase sessiontracker. He modificado el método Dispose () para guardar la actividad de la sesión en DB. Invoqué el método obj.Dispose () cuando un usuario hace clic en el botón de cerrar sesión. Si el usuario cerró el navegador por error, GC llamará al destructor mientras limpia los objetos (no inmediatamente, pero con certeza llamará a este método después de algún tiempo). El método destructor ejecuta internamente el mismo método Dispose () para guardar las actividades de sesión en DB.

-Shan


La sesión está disponible en su archivo Global.asax, durante el evento Session_Start. Tal vez esperar hasta este punto para hacer las cosas?


El evento Session_End se Session_End solo cuando el sessionstate mode está establecido en InProc en el archivo Web.config . Si el modo de sesión está configurado en StateServer o SQLServer , el evento no se StateServer .

use Session["SessionItemKey"] para obtener el valor de la sesión.


Para responder mejor a la pregunta original:

Fondo

Cada solicitud de una sola página hace girar un nuevo objeto de Session y luego lo infla desde su tienda de sesión. Para ello, utiliza la cookie proporcionada por el cliente o una construcción de ruta especial (para sesiones sin cookies). Con este identificador de sesión, consulta el almacén de sesiones y deserializa (es por eso que todos los proveedores, pero InProc debe ser Serializable) el nuevo objeto de sesión.

En el caso del proveedor de InProc, simplemente le entrega la referencia almacenada en HttpCache codificado por el identificador de sesión. Esta es la razón por la cual el proveedor de InProc descarta el estado de la sesión cuando se recicla el AppDomain (y también por qué varios servidores web no pueden compartir el estado de la sesión de InProc .

Este objeto recién creado e inflado está atascado en la colección Context.Items para que esté disponible mientras dure la solicitud.

Cualquier cambio que haga en el objeto Session se mantendrá al final de la solicitud en el almacén de sesiones mediante serialización (o en el caso de InProc, se actualizará la entrada HttpCache ).

Dado que Session_End sin una solicitud actual in-fly, el objeto Session se activa ex-nilo, sin información disponible. Si usa el estado de la sesión InProc, la caducidad de HttpCache desencadena un evento de devolución de llamada en su evento Session_End , por lo que la entrada de la sesión está disponible, pero sigue siendo una copia de lo que se almacenó por última vez en HttpContext.Cache . Este valor se almacena en la propiedad HttpApplication.Session mediante un método interno (llamado ProcessSpecialRequest ), donde está disponible. En todos los demás casos, proviene internamente del valor HttpContext.Current.Session .

Tu respuesta

Como Session_End siempre dispara contra un Contexto nulo, SIEMPRE debe usar esto. Session en ese evento y pasar el objeto HttpSessionState a su código de rastreo. En todos los demás contextos, está perfectamente bien obtener de HttpContext.Current.Session y luego pasar al código de seguimiento. NO deje, sin embargo, que el código de seguimiento se extienda para el contexto de la sesión.

Mi respuesta

No use Session_End menos que sepa que el almacén de sesión que está utilizando admite Session_End , que lo hace si devuelve true de SetItemExpireCallback . La única tienda en la caja que lo hace es la tienda InProcSessionState . Es posible escribir una tienda de sesiones que sí lo hace, pero la pregunta de quién procesará el Session_End es un poco ambigua si hay varios servidores.