2013-04-01 15 views
10

Un sito Web su cui sto lavorando è molto incentrato sui dati. Alcuni report richiedono più di un'ora per essere completati. Ogni volta che un utente invia una richiesta per un report, viene creato un nuovo thread che genera il report. L'utente viene quindi reindirizzato a una pagina in cui viene indicato che il report è in corso e che si desidera aggiornare per scaricare il report. Se l'utente aggiorna nuovamente la pagina e il rapporto è ancora in corso, viene visualizzato lo stesso messaggio; in caso contrario viene fornito un collegamento per il download.Prevenire la scadenza di singole sessioni in base a condizioni personalizzate?

Tutti i rapporti/relazioni utente vengono salvati nella variabile dell'applicazione. Funziona bene, tranne quando l'utente è inattivo per più di 20 minuti (durante l'elaborazione del report), quindi l'utente viene disconnesso; se l'utente si collega nuovamente, il rapporto può ancora essere scaricato.

Non desidero aumentare il tempo di scadenza della sessione, ma ho bisogno di interrompere la scadenza se l'utente ha qualcosa in background, come un report in fase di elaborazione.

In Session_End sono in grado di recuperare il userid e abbinarlo a Application["work"] per vedere che l'utente ha un lavoro in sospeso o meno.

Tuttavia, non ho idea di come posso rinviare la fine della sessione nel caso precedente?


Edit: Ognuno ha suggerito come soluzione da 'il mantenimento di un contatto' a 'utilizzando query string'. "Mantenere il contatto" mi è sembrato il più promettente, ma non riesce nei seguenti scenari: a. Quando il browser è chiuso/calcolato, passa in modalità standby durante il pranzo, ecc. B. Quando l'utente accede a un'altra sezione non-asp.net (è un sito legacy).

Non è possibile annullare l'evento Session_End stesso?

risposta

3

Mentre cerco disperatamente di posticipare l'evento session_end, penso che sembri impossibile?

Il lavoro più semplice che sono riuscito a ottenere era "Utilizzare i cookie" e modificare la mia logica di autenticazione.

Ho implementato un metodo per scrivere una chiave di guida per il cookie denominato admin ogni volta che l'utente ha richiesto il rapporto con scadenza di 9 ore (l'ufficio di tempo massimo sarà aperto per lavoro). Ho salvato questo guid con id utente in una tabella separata.

Nella pagina master in cui stavo verificando la sessione userid ho implementato un altro metodo per controllare qualsiasi cookie denominato admin. Se viene trovato ho impostato la sessione sull'ID utente salvato nella tabella, altrimenti li ho reindirizzati alla pagina di accesso come prima che accadesse.

Sembra funzionare come per magia. Ma ho bisogno di sapere è una cosa giusta?

1

Suggerirei di aumentare il timeout della sessione anziché cercare di aggirare il problema. C'è un filo interessante sessione e forma dai timeout here

+2

Perché dovrei aumentare il timeout della sessione ?? Ho solo bisogno di loro per 2 o 3 utenti che anche in una settimana. Non pensi che sarà uno spreco di risorse ?? quando il 99% del dosatore dell'utente richiede una sessione lunga. – Ratna

4
Maintain a contact with the server will avoid Session Timeout. 

Creare un empty Web service e run that in your server poi call the web service by your site by JQuery dall'intervallo di alcuni secondi è sufficiente per mantenere la sessione viva

Può essere questa soluzione vi aiuterà a ..

Prova questo link per tutti i dettagli: Prevent Session Timeout in ASP.NET

+0

La mia pagina di download ha già un timer jax che aggiorna la pagina in 5 minuti. In ogni caso, le persone dell'amministrazione hanno l'abitudine di fare altre cose che cambiano la posizione della pagina. – Ratna

1

vi suggerisco di non dipendono le sessioni a tutti .. si può dipendere da la stringa di query aggiungendo una nuova variabile GUID e usa quel valore di variabile con l'oggetto applicazione per mappare i file richiesti dall'utente con il valore GUID .. in questo modo .. l'utente sarà sempre in grado di scaricare il file poiché ha il collegamento al file che viene mappato all'oggetto dell'applicazione e non è necessario gestire alcun timeout della sessione.

+0

Caro samir, non credo che sarà possibile dal momento che dovrò cambiare tutto il codice di autenticazione. Il problema non è solo il download del file. L'amministratore a volte unire 2 o più file prima di pubblicare su Amazon, per il quale devo tenere traccia di tutti i file creati da lui. – Ratna

+0

Penso che tu possa usare la mia tecnica solo nelle pagine in cui hai bisogno che l'utente completi l'azione prima che lasci il tuo sistema .. puoi mantenere l'autenticazione come è ora e puoi usare questa tecnica solo per lo scenario di download. –

1

Perché non si tenta di mostrare la barra di avanzamento del file di caricamento e all'interno di quella è possibile utilizzare la logica di controllo dello stato del file scaricato finora. Avrà due vantaggi, dato che stai colpendo il tuo sito web, la sessione non scadrà mentre stai restituendo le informazioni utili all'utente finale.

+0

E come funzionerebbe quando l'utente visita un altro sito? (come dichiarato dall'OP) –

4

Ciò che si può fare è impostare il timeout della sessione su un valore più alto quando si rileva che è stato richiesto un report che richiederà molto tempo.Ciò ovviamente presuppone che sia possibile calcolare se un report richiederà molto tempo per essere eseguito. Se è così, si può fare questo prima di dare il via alla discussione:

Session.Timeout = 120 // set timeout to two hours for this session only 

A parte il ping di una pagina o di un servizio tramite Ajax, non c'è davvero nessun altro modo. (a meno che non fare affidamento su sessioni a tutti è un'opzione).

Questo a causa del modo in cui le sessioni vengono mantenute: il runtime ASP.NET rileva una sessione quando la richiesta contiene un cookie. Questo cookie è impostato ad ogni richiesta/risposta e conterrà una data di scadenza.

Se nella richiesta iniziale si imposta una scadenza di 20 minuti e l'utente chiude il browser o è inattivo per più di 20 minuti non è possibile sul lato server individuare la sessione a cui appartiene la richiesta. Quindi, per rispondere alla domanda se è possibile annullare la sessione_end, non è possibile non farlo mentre il codice esegue il lato server e non può accedere al cookie client. È un evento semplice che viene attivato venti minuti dopo aver impostato l'ultimo cookie. Questo è completamente asincrono dal lato client.

La soluzione che ho proposto è una soluzione che potrebbe funzionare se si sa come calcolare la durata (almeno approssimativamente).

Un'altra soluzione, ma molto più complicata, sarebbe quella di salvare i report e creare una sezione separata per l'utente in cui può vedere tutti i suoi report. In questo modo, anche se la sessione scade, può accedere nuovamente e accedere alla sua cronologia e recuperare il rapporto.

5

La risposta breve

C'è attualmente (che io sappia) modo semplice per prolungare la durata di una sessione di ASP.NET singola. Esiste una soluzione possibile: utilizzare un fornitore di negozio di stato sessione personalizzato!


La risposta lunga

Per prima cosa: Iniziare con qualcosa che è già costruito! Utilizzare l'esempio Session-State Store Provider (and its tutorial) fornito da Microsoft.Questo provider di negozio di stato di sessione di esempio utilizza Microsoft Access come il suo back-end; sebbene, poiché utilizza connessioni ODBC, è possibile avere virtualmente il back-end del database supportato tramite i driver ODBC installati.

Questo provider di negozio di stato di sessione di esempio è semplicemente una versione personalizzata di ciò che ASP.NET utilizza internamente (con l'eccezione che in esecuzione di ASP.NET in memoria).


In secondo luogo: Prepariamo i requisiti di database di Access e la configurazione.

Creare la tabella come specificato nel tutorial e nei commenti del file:

CREATE TABLE Sessions 
(
    SessionId  Text(80) NOT NULL, 
    ApplicationName Text(255) NOT NULL, 
    Created   DateTime NOT NULL, 
    Expires   DateTime NOT NULL, 
    LockDate  DateTime NOT NULL, 
    LockId   Integer NOT NULL, 
    Timeout   Integer NOT NULL, 
    Locked   YesNo  NOT NULL, 
    SessionItems Memo, 
    Flags   Integer NOT NULL, 

    CONSTRAINT PKSessions PRIMARY KEY (SessionId, ApplicationName) 
) 

NOTA: Se si desidera utilizzare SQL Server, è sufficiente sostituire Testo (...) con varchar (...), YesNo con bit e Memo con varchar (MAX).

Add/aggiornare il web.config con il seguente (è possibile utilizzare connectionstrings.com per aiutare a generare una stringa di connessione):

<configuration> 
    <connectionStrings> 
     <add name="OdbcSessionServices" connectionString="DSN=SessionState;" /> 
    </connectionStrings> 

    <system.web> 
     <sessionState 
       cookieless="true" 
       regenerateExpiredSessionId="true" 
       mode="Custom" 
       customProvider="OdbcSessionProvider"> 
      <providers> 
       <add name="OdbcSessionProvider" 
         type="Samples.AspNet.Session.OdbcSessionStateStore" 
         connectionStringName="OdbcSessionServices" 
         writeExceptionsToEventLog="false" /> 
      </providers> 
     </sessionState> 
    </system.web> 
</configuration> 

Terzo: Aggiunta di una funzione che si estenderà per altro rispetto allo Timeout specificato.

Eseguire una copia della funzione ResetItemTimeout, e il nome ResetItemTimeout2:

var ExtendedTotalMinutes = 2 * 60; // hours * minutes 

public override void ResetItemTimeout2(HttpContext context, string id) 
{ 
    OdbcConnection conn = new OdbcConnection(connectionString); 
    OdbcCommand cmd = 
     new OdbcCommand("UPDATE Sessions SET Expires = ? " + 
      "WHERE SessionId = ? AND ApplicationName = ?", conn); 
    cmd.Parameters.Add("@Expires", OdbcType.DateTime).Value 
     = DateTime.Now.AddMinutes(ExtendedTotalMinutes); // IMPORTANT!! Set your total expiration time. 
    cmd.Parameters.Add("@SessionId", OdbcType.VarChar, 80).Value = id; 
    cmd.Parameters.Add("@ApplicationName", OdbcType.VarChar, 255).Value = ApplicationName; 

    try 
    { 
     conn.Open(); 

     cmd.ExecuteNonQuery(); 
    } 
    catch (OdbcException e) 
    { 
     if (WriteExceptionsToEventLog) 
     { 
      WriteToEventLog(e, "ResetItemTimeout"); 
      throw new ProviderException(exceptionMessage); 
     } 
     else 
      throw e; 
    } 
    finally 
    { 
     conn.Close(); 
    } 
} 

Quarto: Sostenere l'estensione di una singola sessione ASP.NET!

Ogni volta che si necessità di estendere una sessione, chiama la funzione ResetItemTimeout come segue:

using Samples.AspNet.Session; 

// from inside a User Control or Page 
OdbcSessionStateStore.ResetItemTimeout2(this.Context, this.Session.SessionID); 

// --or-- 

// from anywhere else 
OdbcSessionStateStore.ResetItemTimeout2(System.Web.HttpContext.Current, System.Web.HttpContext.Current.Session.SessionID); 

Note

  1. Leggere il comments sulla pagina con il campione Provider del negozio di stato di sessione;

    • C'è una potenziale buona entrata di un errore in GetSessionStoreItem quando si utilizza GetItem.

    • Un'altra buona è che timestamp UTC dovrebbe essere.

  2. ci sono evidenti miglioramenti delle prestazioni/manutenibilità che potrebbe essere fatto (in particolare di avere il codice duplicato in ResetItemTimeout e ResetItemTimeout2).

  3. Ho non testato questo codice!


modifiche

  • mi sono reso conto che ho perso la parte in cui si desidera estendere più rispetto al Timeout - risposta è stato completamente aggiornato.
  • Aggiunta la sezione delle note a piè di pagina.
+0

Jesse ho provato a implementarlo, ma ha aumentato notevolmente il tempo di caricamento. – Ratna

+0

Hai provato a usare SQL come back-end, invece di MS Access? Che ne dici di usare 'SqlConnection' invece di' OdbcConnection' (sostituisci tutto Odbc con Sql)? – Jesse

+0

il nostro intero progetto è su ms sql quindi non c'è bisogno di usare come accesso. in realtà abbiamo impiantato questo b4 anche perché avevamo bisogno di passare i valori di sessione tra i classici asp e asp.net. – Ratna

2

Affinché una sessione rimanga attiva, qualcosa (non necessariamente il browser dell'utente) deve fare una richiesta alla tua app con il cookie ASP.NET_SessionId di quell'utente ogni tanto.

E se avessi un codice che salva ASP.NET_SessionId degli utenti che ti interessano, e poi hai un servizio Windows che richiede una pagina sulla tua app con gli ASP.NET_SessionId richiesti ogni 20 minuti o così.

vedere http://erlend.oftedal.no/blog/?blogid=41 per alcune informazioni su questo cookie

2

Si sta utilizzando FormsAuthentication? In tal caso, è possibile aumentare il timeout per il ticket di autenticazione, che impedirà la schermata di accesso anche dopo che la sessione è scaduta.

All'inizio della richiesta è possibile controllare l'utente tramite il ticket Dopo aver ottenuto l'utente se la sessione è nullo significa che l'utente è stato offline per un po ', è possibile controllare il lavoro in corso per quell'utente.

Se l'utente ha un lavoro in corso, caricare i valori di sessione che potrebbero essere necessari e reindirizzarli al lavoro in corso o segnalare per il download.

Se l'utente non ha nulla, fa scadere il ticket e li reindirizza alla pagina di accesso o semplicemente li tiene loggati e ricarica i valori di sessione.

Il timeout per il ticket di autenticazione è abbastanza grande http://msdn.microsoft.com/en-us/library/system.web.configuration.formsauthenticationconfiguration.timeout.aspx

Acclamazioni

3

E 'meglio non fare affidamento su Session_End in quanto non sempre il fuoco, come ad esempio quando il processo di lavoro ricicla o un'eccezione non rilevata si verifica, cioè viene praticamente ucciso/rimbalzato.

Se si desidera riattivare una sessione, sembra che il modo migliore sia archiviare i dati utente in qualche modo e gestire completamente la cache.

Dalla tua risposta ai post precedenti sembra che l'attività di rete aggiuntiva e il successivo caricamento del tempo di pagina aumentino quando si utilizza la gestione dello stato sql sono inaccettabili e la differenza tra l'utilizzo del provider dello stato del server SQL per l'utilizzo di un server di sessione come Microsoft AppFabric trascurabile, tuttavia sembra una chiara possibilità che se si dovesse utilizzare il server di sessione di AppFabric accoppiato con il suo caching, le cose potrebbero essere velocizzate molto.

P.S. In generale, eliminando le sessioni sembrerebbe la soluzione più efficiente, vedi la risposta di John Han in questo post, quasi riassumendo lo sessions are bad mmkay.

Problemi correlati