2010-07-29 10 views
8

Abbiamo un'applicazione MVC.NET che rileva errori irreversibili al riavvio. Nel nostro gestore di eventi Session_Start, aggiungiamo l'id di sessione a un dizionario. Nel gestore Session_End, lo rimuoviamo. Si consideri la seguente sequenza di richieste:L'applicazione ASP.NET MVC attiva Session_Start più volte per una singola sessione

GET home.mvc
< applicazione riavvia >
GET main.css
GET banner.jpg
GET somedata.mvc
...

A causa del modo in cui l'applicazione è progettata, questo tipo di sequenza si verifica abbastanza frequentemente se si esegue una ricostruzione mentre l'applicazione è aperta in una finestra del browser. Non sarebbe terribilmente preoccupante se non che lo vedo anche negli ambienti di produzione. Ad esempio, si verificherà (anche se raramente) quando si modifica web.config.

Le richieste successive al riavvio sono tutte dovute ai collegamenti nella home page o alle chiamate AJAX da JavaScript.

Quello che osservo è che .NET gestisce le prime 5 richieste in parallelo. Ciascuna richiesta di questo tipo attiva l'evento Session_Start. Dopo un breve periodo, l'evento Session_End viene attivato 3 volte. Per essere chiari, ogni Session_Start corrisponde alla stessa identica sessione. Hanno tutti lo stesso ID di sessione e la proprietà IsNewSession è vera per tutti gli oggetti dello stato di sessione. Inoltre, gli eventi Session_End fanno non corrispondono alla sessione che viene uccisa. La sessione persiste, insieme ai dati memorizzati nello stato della sessione.

Ho bisogno di impedirgli di lanciare Session_Start più di una volta o di capire come dire quando Session_End non significa realmente che la sessione è terminata.

+0

Che cosa è necessario affrontare? Stai dicendo che c'è una discrepanza tra il tuo dizionario e il dizionario interno di asp.net? A che punto trovi la discrepanza? –

+0

Il dizionario è memorizzato in una variabile di applicazione o in una variabile di sessione? –

+0

Il dizionario è una variabile di applicazione. –

risposta

3

La risposta a questa domanda si è rivelata abbastanza facile, in avanti, anche se il comportamento era certamente confuso.

Normalmente, MVC sincronizzerà tutte le richieste di un'applicazione sul blocco dello stato di sessione dell'applicazione (poiché il modulo http di MVC è contrassegnato come richiedente lo stato di sessione). Nel mio scenario, l'applicazione si riavvia dopo aver servito la pagina principale. Pertanto, quando arrivano le richieste relative alla pagina principale, non esiste ancora lo stato di sessione per quell'ID di sessione e le richieste vengono eseguite in parallelo.

Vedo 5 richieste parallele perché sto sviluppando su XP e le versioni desktop di IIS sono limitate a 5 richieste simultanee. Poiché l'oggetto stato sessione non esiste per nessuna di queste richieste, ogni richiesta crea un nuovo oggetto stato sessione e attiva Session_Start. Quattro delle richieste passano ai metodi di azione MVC. Poiché questi richiedono lo stato di sessione, .NET tenta di sincronizzare gli oggetti dello stato di sessione creati con il backing store una volta completate le richieste.

Solo la prima sincronizzazione può riuscire. .NET scarta semplicemente i tre oggetti di stato sessione aggiuntivi e lancia Session_End per ognuno. .NET non tenta di sincronizzare il quinto stato oggetto di sessione con il backing store perché è stato creato per un modulo http asincrono che è contrassegnato come richiedente lo stato di sessione readonly.

Quindi, la correzione ha due parti:

(1) Nel mio gestore Session_Start, ora verificare se l'oggetto lo stato della sessione è di sola lettura. Se lo è, allora ritorno immediatamente senza fare nulla. .NET non licenzierà un Session_End corrispondente e quindi tutto ciò che faccio non verrà pulito in modo appropriato.

(2) Ora tengo un conteggio dei riferimenti nel mio dizionario. Incremento il conteggio ogni volta che un gestore Session_Start tenta di aggiungere un ID sessione e lo decrementa ogni volta che Session_End tenta di rimuoverne uno. Una volta che il conteggio raggiunge 0, rimuovo l'ID di sessione dal mio dizionario.

+0

è un po 'vecchio .. ma non sto seguendo perché le 5 richieste sono in parallelo. Viene generato da una singola richiesta? Perché vengono creati 5 allo stesso tempo? –

+0

Più richieste vengono create contemporaneamente perché il browser invia più richieste senza attendere che vengano restituite. (Dopo aver ricevuto la pagina Web, il browser richiede immediatamente tutte le immagini di riferimento, i fogli di stile e così via.) Il numero 5 viene visualizzato perché la macchina era una scatola di Windows XP. IIS limita le applicazioni all'elaborazione di 5 richieste simultanee su macchine desktop. Su una casella del server, il numero sarebbe stato più alto. –

1

L'ID di sessione può essere riutilizzato se il client invia un valore scaduto. Leggi su attributo regenerateExpiredSessionId il <sessionState> dell'elemento here e si noti che il valore predefinito è "true"

Si potrebbe anche trovare this interessante:

+0

Grazie per la tua risposta Matt, ma credo di aver abbaiato l'albero sbagliato. Aggiornerò la mia domanda con alcune informazioni aggiuntive che ho scoperto ieri. –

0

Mi è capitato questo caso per una vecchia app ASP.NET in fase di sviluppo - ho scoperto che RequireSSL era impostato su True per i cookie ... il che ovviamente significava che il cookie di sessione non era stato mantenuto/ri-emesso da il client (localhost, non SSL) - quindi le richieste successive hanno creato nuove sessioni.

Problemi correlati