2010-07-29 24 views
8

Tenemos una aplicación MVC.NET que encuentra errores fatales cuando se reinicia. En nuestro controlador de eventos Session_Start, agregamos la identificación de la sesión a un diccionario. En el controlador Session_End, lo eliminamos. Considere la siguiente secuencia de solicitudes:La aplicación ASP.NET MVC dispara Session_Start varias veces para una sola sesión

GET home.mvc
< aplicación reinicia >
GET main.css
GET banner.jpg
GET somedata.mvc
...

Debido a la forma en que se diseña la aplicación, este tipo de secuencia ocurre con bastante frecuencia si realiza una reconstrucción mientras la aplicación está abierta en una ventana del navegador. Eso no sería terriblemente preocupante, excepto que también lo veo en entornos de producción. Por ejemplo, ocurrirá (aunque raramente) cuando edite web.config.

Las solicitudes que siguen al reinicio se deben a enlaces en la página de inicio o llamadas AJAX desde JavaScript.

Lo que observo es que .NET maneja las primeras 5 solicitudes en paralelo. Cada solicitud hace que desencadene el evento Session_Start. Después de un corto tiempo, dispara el evento Session_End 3 veces. Para que quede claro, cada Session_Start corresponde a la misma sesión. Todos tienen el mismo ID de sesión y la propiedad IsNewSession es verdadera para todos los objetos de estado de sesión. Además, los eventos Session_End hacen no corresponden a la sesión que se está matando. La sesión persiste, junto con los datos almacenados en el estado de la sesión.

Necesito evitar que active Session_Start más de una vez o descubrir cómo saber cuándo Session_End realmente no significa que la sesión ha finalizado.

+0

¿Qué es lo que tiene que tratar? ¿Estás diciendo que hay una discrepancia entre tu diccionario y el diccionario interno de asp.net? ¿En qué momento encuentras la discrepancia? –

+0

¿El diccionario está almacenado en una variable de aplicación o en una variable de sesión? –

+0

El diccionario es una variable de aplicación. –

Respuesta

3

La respuesta a esta pregunta resultó ser bastante sencilla foward, aunque el comportamiento fue ciertamente confuso.

Normalmente, MVC sincronizará todas las solicitudes a una aplicación en el bloqueo de estado de la sesión de la aplicación (porque el módulo http de MVC está marcado como que requiere estado de sesión). En mi caso, la aplicación se reinicia después de servir la página principal. Por lo tanto, cuando entran las solicitudes relacionadas con la página principal, todavía no existe un estado de sesión para esa ID de sesión y las solicitudes se ejecutan en paralelo.

Veo 5 solicitudes paralelas porque estoy desarrollando en XP y las versiones de escritorio de IIS están limitadas a 5 solicitudes concurrentes. Como el objeto de estado de sesión no existe para ninguna de estas solicitudes, cada solicitud crea un nuevo objeto de estado de sesión y activa Session_Start. Cuatro de las solicitudes van a los métodos de acción de MVC. Dado que estos requieren el estado de la sesión, .NET intenta sincronizar los objetos de estado de sesión creados con el almacén de respaldo una vez que se completan las solicitudes.

Solo la primera sincronización puede tener éxito. .NET simplemente descarta los tres objetos de estado de sesión extra y dispara Session_End para cada uno. .NET no intenta sincronizar el objeto de estado de la quinta sesión con el almacén de respaldo porque se creó para un módulo http asíncrono que está marcado como que requiere un estado de sesión de solo lectura.

Por lo tanto, la revisión tiene dos partes:

(1) En mi manejador Session_Start, ahora comprobar si el objeto de estado de sesión es de sólo lectura. Si es así, entonces regreso de inmediato sin hacer nada. .NET no activará un Session_End correspondiente y, por lo tanto, cualquier cosa que haga no se limpiará correctamente de todos modos.

(2) Ahora mantengo un recuento de referencias en mi diccionario. Incremento el recuento cada vez que un controlador Session_Start intenta agregar una identificación de sesión y la disminuye cada vez que Session_End intenta eliminar una. Una vez que el recuento llega a 0, elimino la identificación de la sesión de mi diccionario.

+0

es un poco viejo ... pero no estoy siguiendo por qué las 5 solicitudes están en paralelo. ¿Esto se genera a partir de una sola solicitud? ¿Por qué se crean 5 al mismo tiempo? –

+0

Se crean varias solicitudes al mismo tiempo porque el navegador envía varias solicitudes sin esperar a que vuelvan. (Después de recibir la página web, el navegador solicita inmediatamente todas las imágenes, hojas de estilo, etc.). El número 5 aparece porque la máquina era una caja de Windows XP. IIS limita las aplicaciones al procesamiento de 5 solicitudes simultáneas en máquinas de escritorio. En un cuadro de servidor, el número habría sido mayor. –

1

La identificación de la sesión puede reutilizarse si el cliente le envía un valor que ha expirado. Lea sobre regenerateExpiredSessionId atributo de la > del elemento < sessionState here y observe que el valor por defecto es "verdadero"

También puede encontrar this interesante:

+0

Gracias por su respuesta Matt, pero creo que he estado ladrando el árbol equivocado. Actualizaré mi pregunta con información adicional que descubrí ayer. –

0

Me sucedió esto en una aplicación ASP.NET antigua en desarrollo - Resultó que RequireSSL se estableció en True para las cookies ... lo que por supuesto significaba que la cookie de sesión no se guardaba/re-emitía el cliente (localhost, no SSL) - por lo que las solicitudes posteriores crearon nuevas sesiones.

Cuestiones relacionadas