Pregunta

Recientemente, mientras trabajaba en algún código para un proyecto ASP.NET en el trabajo. Necesitábamos una utilidad de seguimiento para tomar métricas básicas sobre la actividad del usuario (recuento de visitas a la página, etc.), las rastrearíamos en Session , luego guarde los datos en la base de datos a través de Session_End en Global.asax .

Comencé a hackear, el código inicial funcionó bien, actualizando el DB en cada carga de página. Sin embargo, quería eliminar este hit de DB en cada solicitud y solo confiar en Session_End para almacenar todos los datos.

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

El problema es que cuando ejecuté Tracker.Log () en el método Session_End , el HttpContext.Current.Session en el código del rastreador fue fallando con un 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 realmente parece funcionar bien (terminé inyectándolo en el rastreador) ..

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

Gracias de antemano chicos, agradezco el aporte. :)

¿Fue útil?

Solución

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

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

HOWEVER

Su aplicación puede crear múltiples instancias de HttpApplication para manejar solicitudes paralelas, y estas instancias se pueden reutilizar, por lo que simplemente recogerla de alguna manera no 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 el inicio de sesión en cada página probablemente no sea una gran idea, pero tal vez sea una casa intermedia con algún registro asincrónico que suceda: activa los detalles en una clase de registro, que de vez en cuando registra los detalles que busca, aún no es 100% sólido si la aplicación falla, pero es menos probable que pierda todo.

Otros consejos

Para responder mejor a la pregunta original:

Fondo

Cada solicitud de página hace girar un nuevo objeto Session y luego lo infla desde su tienda de sesiones. Para hacer esto, 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 sesión y deserializa (es por eso que todos los proveedores, excepto InProc, deben ser serializables) el nuevo objeto de sesión.

En el caso del proveedor de InProc, simplemente le entrega la referencia que almacenó en el HttpCache tecleado por el identificador de sesión. Esta es la razón por la cual el proveedor de InProc deja el estado de 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 realice en el objeto Session se conserva al final de la solicitud en el almacén de la sesión serializando (o en el caso de InProc, la entrada HttpCache se actualiza).

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

Tu respuesta

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

Mi respuesta

No utilice Session_End a menos que sepa que el almacén de sesiones 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 un almacén de sesión que lo haga, pero la pregunta de quién procesará el Session_End es un tanto ambiguo si hay varios servidores.

Creo que ya respondió su propia pregunta: generalmente 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 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 que no puede confiar en el evento de finalización de sesión en ningún caso? Solo funcionará mientras tenga el estado de sesión en proceso. Cuando se utiliza el servidor SQL o StateServer para gestionar el estado de la sesión, el evento de finalización de la sesión no se activará.

El evento Session_End se genera solo cuando el sessionstate mode se establece en InProc en el Web.config expediente. Si el modo de sesión se establece en StateServer o SQLServer , el evento no se genera.

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

Bien, estoy en el mismo problema para rastrear la actividad de la sesión. En lugar de utilizar el evento session_end, he implementado la interfaz IDisposable y el destructor en mi clase de tracker de sesión. 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 Cerrar sesión. Si el usuario cerró el navegador por error, GC llamará al destructor mientras limpia los objetos (no de inmediato, pero seguro que 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 la sesión en la base de datos.

-Shan

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

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

¿Moral? No use Session_End.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top