2012-01-18 12 views
9

Ho un'azione MVC di lunga durata (4-10 secondi) che esegue un report da una chiamata AJAX. Mentre è in esecuzione, gli utenti possono modificare i parametri ed eseguire qualcos'altro, quindi annullo la richiesta AJAX prima di crearne un'altra.Come si annulla un lato client di azione MVC AJAX long running (in javascript)?

Così, per esempio (ad esempio in jQuery, ma il problema si verifica a prescindere):

// If we have an active request and it's not complete 
if(dataRequest && dataRequest.readyState != 'complete') 
{ 
    dataRequest.abort(); 
} 

dataRequest = $.ajax(...); 

lato client questo sembra funzionare bene, ma la richiesta cancellato è ancora in esecuzione sul server. Ad esempio se il report impiega 10 secondi, e ne annullo uno e avvio l'altro, la seconda richiesta impiega 20 secondi.

penso che questo sia dovuto al session level locking:

[Se] due richieste simultanee sono fatti per la stessa sessione (utilizzando lo stesso valore di SessionID), la prima richiesta ottiene l'accesso esclusivo al il informazioni sulla sessione. La seconda richiesta viene eseguita solo dopo che è stata completata la prima richiesta .

Quindi la seconda richiesta non può accedere alla sessione fino al termine del primo. L'utilizzo di azioni MVC asincrone non sembra aggirarlo poiché l'azione deve ancora essere in grado di apportare modifiche alla sessione.

È possibile interrompere un'azione e avviare la successiva senza utilizzare AsyncController o [SessionState(SessionStateBehavior.ReadOnly)]?

Se non è necessario?

risposta

4

Come si scopre la risposta completa richiesti due cose:

primo luogo (grazie Darin per confirming it) la sessione blocca essenzialmente le pagine da eseguire uno dopo l'altro. Further investigation ha indicato che questo è un problema più generale con le sessioni ASP.Net - semplicemente non possono gestire la concorrenza ottimistica.

In secondo luogo, la richiesta annullata deve verificare se il client è ancora connesso. Ci sono situazioni in cui potresti voler continuare (come un incendio e dimenticare l'azione ASP) ma in questo caso se il cliente non sta più aspettando il rapporto, non ha senso continuare a elaborarlo.

Questo è disponibile come property of the response: this.Response.IsClientConnected

Quindi, per cancellare in modo efficace la mia azione lato server quando jQuery fatto richiesta ho dovuto scrivere il mio gestore di sessione e aggiungere controlli regolari contro this.Response.IsClientConnected.

+1

Fai attenzione a "IsClientConnected' perché può sembrare un serio problema di prestazioni per controllarlo, vedi http://stackoverflow.com/questions/9094735/when-is-response-isclientconnected-slow – Keith

+0

Ciao Keith! Ho un problema simile ma non ho potuto risolverlo nemmeno con la tua risposta, (http://stackoverflow.com/questions/29235850/how-to-abort-long-running-ajax-request-in-net-mvc-4) C'è un modo per aiutarmi? Oppure potresti pubblicare un tuo codice di esempio per attivare 'this.Response.IsClientConnected' –

4

[SessionState(SessionStateBehavior.ReadOnly)] o la disattivazione completa della sessione è sufficiente per consentire l'accesso simultaneo alle azioni del controller dalla stessa sessione. Quindi la seconda richiesta (dalla stessa sessione) non ha bisogno di attendere il completamento del primo prima di essere elaborato. Per quanto riguarda la cancellazione della prima azione sul server, beh, sarà più difficile. È necessario associare ciascuna attività a un ID univoco e quando viene avviata una nuova attività, restituire questo ID attività al client. Quindi, quando si annulla la richiesta AJAX sul client chiamando .abort(), è possibile attivare un'altra richiesta AJAX su un'altra azione del controller e passarla all'ID attività univoca. L'azione controller stessa imposterà alcuni flag comuni per indicare la prima azione da interrompere.

Il TPL dispone di un supporto di annullamento incorporato che è possibile dare un'occhiata per semplificare tale procedura al fine di evitare una struttura di dati condivisa tra i 2 che li sincronizzerà.

+0

Sto già usando il TPL per fare un sacco di lavoro che sta prendendo il tempo - sto eseguendo circa 25 secondi di codice consecutivo di lunga durata in parallelo 4-10s. Comunque usarlo per gestire l'abort sembra reinventare la ruota; perché la nuova richiesta deve dire al vecchio (ancora in esecuzione) quello di abortire quando è già stato cancellato? – Keith

+1

@ Keith, non è la nuova richiesta che dirà ai vecchi di abortire. Devi inviare una nuova richiesta speciale AJAX per dire al server di interrompere l'elaborazione di una particolare attività. Quando esegui 'dataRequest.abort();' stai solo interrompendo la richiesta AJAX ma se vuoi interrompere l'elaborazione lato server devi fare molto più lavoro di quello. –

+0

Hmm, quindi IIS non sa che la richiesta è stata annullata a livello di trasporto? Mi sarei aspettato che il thread della pagina venisse interrotto a livello di IIS/ASP quando la connessione in attesa è terminata a livello di trasporto. – Keith

1

.abort() è solo la cancellazione lato client. Se si desidera monitorarlo sul lato server, uno dei modi migliori per farlo è quello di interrogare la proprietà IsClientConnected, che ti dirà qual è lo stato della comunicazione ajax.

+1

Vedere la risposta accettata e la domanda originale. Questa risposta non aggiunge nulla non già dichiarato. State anche estremamente attenti usando 'IsClientConnected' dato che può apparentemente essere un serio problema di prestazioni per controllarlo, vedere http://stackoverflow.com/questions/9094735/when-is-response-isclientconnected-slow (a quanto pare può costare fino a ½s per controllarlo, ma nessuno è stato in grado di confermare) – Keith

+0

Hai ragione, ho letto il tuo post e devo rivedere la mia opinione. – Dave

Problemi correlati