5

Ho un processo che vorrei eseguire in background. Questo viene eseguito con un clic di un link di azione.Torna alla vista con attesa asincrona

Azione chiamare:

public async Task<ActionResult> ProcessRec() 
    { 
     await Task.Run(() => waitTimer()); 
     return RedirectToAction("Index", "Home"); 
    } 

    public void waitTimer() 
    { 
     Thread.Sleep(10000); 
    } 

Questa attende comunque per il pieno 10 secondi prima di me reindirizzamento al mio "Index, casa" l'azione. Sono molto nuovo in Await/Async quindi so che sto interpretando qualcosa di sbagliato qui. Come faccio a ottenere l'applicazione per tornare a questa azione, mentre il waitTimer è in esecuzione in background? Grazie!!

+0

Quale versione di .NET stai usando. .NET 4.5.2 ha introdotto una funzionalità per rendere questo "corretto" più facile. –

+1

Sto usando .NET 4.5 –

+0

Ho modificato il titolo. Per favore vedi, "[Le domande dovrebbero includere" tag "nei loro titoli?] (Http://meta.stackexchange.com/questions/19190/)", dove il consenso è "no, non dovrebbero". –

risposta

4

await, come hai scoperto, blocca la risposta dal ritorno all'utente prima che sia terminata. Normalmente dovresti mettere il tuo lavoro in background su un altro thread e impostarlo su "fire and forget" non aspettando, tuttavia in ASP.NET IIS chiuderà AppDomains che non vengono utilizzati e non informa IIS che il tuo thread in background " sta utilizzando l'AppDomain "in modo che il thread in background possa essere terminato con un Thread.Abort() durante un arresto di AppDomain.

Se si utilizza .NET 4.5.2 o successivo, è possibile indicare a IIS che si dispone di un worker in background che è necessario mantenere in vita tramite QueueBackgroundWorkItem. Si potrebbe usare in questo modo

public ActionResult ProcessRec() 
    { 
     HostingEnvironment.QueueBackgroundWorkItem(waitTimer); 
     return RedirectToAction("Index", "Home"); 
    } 

    public void waitTimer(CancellationToken token) 
    { 
     Thread.Sleep(10000); 
    } 
    //You also could do 
    public async Task waitTimer2(CancellationToken token) 
    { 
     await Task.Delay(10000); 
    } 

Ora, questo non garantisce che IIS non spegnere il dominio applicazione ma non farle sapere siete nel bel mezzo di qualcosa e chiede più tempo quando non tenta di spegnerlo (si ottengono fino a 90 secondi aggiuntivi dopo l'avvio di uno spegnimento per completare tutti gli elementi di sfondo in coda per impostazione predefinita).

Per ulteriori informazioni leggere this MSDN blog introducendolo.

+0

No HostingEnvironment.QueueBackgroundWorkItem in 4.5 – rnofenko

+1

Ha detto .NET 4.5.2. –

+0

Ho aggiornato alla 4.5.2 e quanto sopra funziona perfettamente per le mie esigenze! Molto apprezzato! –

1

Sto pensando di inviare un messaggio a una coda (come la memoria di azure/coda di servizio) in modo da poter ottenere immediatamente la risposta.

e quindi creare un altro servizio per annullare l'accodamento e elaborare il messaggio (eseguire il vostro compito lungo in esecuzione)

Anche se questo è un sito di azzurro (web app), è possibile utilizzare il lavoro web!

Spero che questo aiuti.

2

Questo tuttavia attende per tutti i 10 secondi prima di reindirizzarmi alla mia azione "Indice, Casa".

Esatto, perché await attende in modo asincrono il completamento delle operazioni. Restituirà il thread alla piscina fino al completamento dell'operazione.

Come si ottiene l'applicazione per tornare a questa azione, mentre waitTimer è in esecuzione in background?

Task.Run è pericoloso in quanto non registra il lavoro con IIS which can lead to problems. Invece, è possibile utilizzare BackgroundTaskManager o HangFire che registrano è l'esecuzione con ASP.NET:

BackgroundTaskManager.Run(() => { waitTimer() }; 
return RedirectToAction("Index", "Home"); 
+0

Le due librerie collegate sono ottime alternative se non è possibile eseguire l'aggiornamento alla 4.5.2 per usare 'QueueBackgroundWorkItem'. –

+0

@Scott Sì, ho visto che ha detto .NET 4.5 :) –