2013-02-07 14 views
5

Ho testato async in WebForms e, per una volta, la mia domanda non riguarda come fare qualcosa, ma come funziona qualcosa che funziona già, funziona. Questo è il mio codice di prova:Async/Await in WebForms - In che modo viene eseguita la continuazione prima del termine del ciclo di vita della pagina?

protected override void OnPreRender(EventArgs e) 
{ 
    Response.Write("OnPreRender<Br>"); 
} 
protected override void OnPreRenderComplete(EventArgs e) 
{ 
    Response.Write("OnPreRenderComplete<Br>"); 
} 
protected async override void OnLoadComplete(EventArgs e) 
{ 
    Response.Write("OnLoadComplete<br>"); 
    var t1 = Task.Factory.StartNew(() => { 
     System.Threading.Thread.Sleep(2000); 
     return 1; 
    }); 

    //This actually does run: 
    Response.Write((await t1).ToString()); 
} 

Quindi il mio compito si ferma per un po 'e poi scrive il risultato. La mia domanda è - non mi aspetto che funzioni perché il controllo è stato restituito dal metodo OnLoadComplete - mi aspetto che la pagina finisca effettivamente il rendering e che venga restituita al client prima che il mio compito venga restituito.

L'uscita effettiva è:

OnLoadComplete 
OnPreRender 
1OnPreRenderComplete 

Quindi è chiaro che il metodo OnLoadComplete prodotto controllo in modo che OnPreRender poteva correre e quindi il controllo restituito al OnLoadComplete. Il mio risultato atteso era che il "1" non avrebbe mai stampato perché gli eventi successivi avrebbero sparato e il thread della pagina sarebbe stato ucciso o la scrittura post-attività sarebbe avvenuta dopo che la risposta fosse stata inviata. Immagino, visto quanto detto sopra, non sorprende che anche se indugio per 10 secondi, il risultato è esattamente lo stesso.

Suppongo che ci sia del cablaggio nel motore WebForm che assicura che tutte le attese siano completate prima che la fase successiva del ciclo di vita della pagina sia proseguita. Qualcuno sa per certo come succede? Ho paura di usare async/attendi nei metodi che devono essere completati prima degli altri eventi per timore che la continuazione sia troppo tardi, ma se è gestita internamente, allora non mi preoccuperò.

risposta

11

Per ASP.NET, è necessario utilizzare solo i metodi async su .NET 4.5. Spiegherò perché alla fine.

Ho an article on SynchronizationContext che aiuta a riempire gli spazi vuoti su come funziona su ASP.NET. Innanzitutto, nota che ASP.NET supportava operazioni asincrone molto tempo fa (.NET 2.0 IIRC). È possibile registrare operazioni asincrone in modi diversi, ma per questa descrizione ci concentreremo su SynchronizationContext.OperationStarted.

ASP.NET crea un SynchronizationContext per ogni richiesta e sa che la richiesta non è completa fino al completamento di tutte le operazioni registrate (chiamando SynchronizationContext.OperationCompleted). Event-based asynchronous pattern components (ad esempio BackgroundWorker) notificherà automaticamente il numero SynchronizationContext all'avvio e al completamento.

Analogamente, i metodi async void (il nuovo task-based asynchronous pattern) notificheranno automaticamente il numero SynchronizationContext all'avvio e al completamento. Pertanto, quando si sostituisce OnLoadComplete come metodo async void, il compilatore inserisce il codice che chiamerà OperationStarted all'inizio e OperationCompleted al termine.

Fin qui tutto bene - ASP.NET ora sa di mantenere attiva la richiesta finché tutte le operazioni asincrone per quella richiesta non sono state completate. Questo è vero anche se non ci sono thread che elaborano la richiesta.

Ora l'avvertenza: ASP.NET prima che .NET 4.5 gestisse questo a un livello richiesta . In ASP.NET 4.5, la pipeline del ciclo di vita è stata resa più intelligente, in modo da ritardare il ciclo di vita della pagina fino al completamento delle operazioni asincrone. Con il vecchio ASP.NET, i gestori "pre" iniziano a in quel punto della pipeline ma potrebbero non terminare più tardi. Il nuovo ASP.NET ritarderà il resto dell'esecuzione della pagina per assicurare i gestori async completi prima di proseguire nel ciclo di vita.

Inoltre, ASP.NET 4.5 rileva se è stato utilizzato un gestore async dove non ce ne dovrebbe essere uno e informa l'utente dell'errore.

Problemi correlati