In ASP.NET 4.5 possiamo eseguire operazioni asincrone sfruttando le keyword async e await di C# 5. Per esempio, in un controller ASP.NET MVC è sufficiente il codice in basso per poter eseguire la chiamata a SomeMethodAsync su un altro thread, liberando il thread di IIS:
public async Task<ActionResult> SomeAction() { await SomeMethodAsync(); return this.View(); } private async Task SomeMethodAsync() { await FirstOperationAsync(); await SecondOperationAsync(); }
Nell'esempio in alto, è il framework stesso a predisporre un SynchronizationContext che si occupa di effettuare il marshalling del codice nel contesto di richiesta originale, una volta che l'operazione asincrona è terminata. Questa funzionalità è sicuramente molto comoda, perchè ci permette di trascurare i dettagli su cosa sta accadendo dietro le quinte, rendendo il codice molto simile a quello che scriveremmo nel caso fosse sincrono.
Non bisogna mai dimenticare, però, che in realtà ciò che effettivamente accade è più complesso e può avere delle implicazioni non immediatamente prevedibili. Un esempio è il caso di un'operazione di tipo fire and forget, di cui cioé non attendiamo il risultato prima del completamento, come nell'esempio in basso:
public ActionResult SomeAction() { // non usiamo await, avviamo l'operazione senza attendere il completamento SomeMethodAsync(); // ritorniamo il risultato prima che l'invocazione // a SomeMethodAsync sia terminata return this.View(); } private async Task SomeMethodAsync() { // queste operazioni potrebbero generare un deadlock await FirstOperationAsync(); await SecondOperationAsync(); }
Quando l'esecuzione di FirstOperationAsync termina, il contesto di richiesta originale potrebbe non essere più disponibile, perché la view è stata già ritornata al browser e la richiesta si è effettivamente chiusa; ciò impedisce al SynchronizationContext di effettuare il marshalling, di fatto bloccando l'esecuzione di SomeMethodAsync.
Il modo corretto per ovviare a questo problema è quello di utilizzare l'opzione ConfigureAwait(false):
private async Task SomeMethodAsync() { await FirstOperationAsync().ConfigureAwait(false); await SecondOperationAsync().ConfigureAwait(false); }
In questo modo, il framework non tenterà di ripristinare il contesto di richiesta originale, consentendo quindi al task asincrono di terminare correttamente anche se questo non è più disponibile.
Commenti
Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.
Approfondimenti
Le novità di Angular: i miglioramenti alla CLI
Usare le navigation property in QuickGrid di Blazor
Utilizzare il nuovo modello GPT-4o con Azure OpenAI
Migliorare l'organizzazione delle risorse con Azure Policy
Supporto ai tipi DateOnly e TimeOnly in Entity Framework Core
Il nuovo controllo Range di Blazor 9
La gestione della riconnessione al server di Blazor in .NET 9
Utilizzare Container Queries nominali
Gestire i dati con Azure Cosmos DB Data Explorer
Potenziare la ricerca su Cosmos DB con Full Text Search
Generare HTML a runtime a partire da un componente Razor in ASP.NET Core
Effettuare il binding di date in Blazor
I più letti di oggi
- Community Night@Basta!Italia on tour 2009 - Milano
- Real Code Day - Firenze
- Real Code Conference 4.0 - Firenze
- Windows Phone r8me - Roma
- Visual Studio 2008 Team Suite in RTM su MSDN Download
- Rilasciata la prima CTP del .NET Parallel Framework
- Annunciata la modalità di uscita di ADO.NET Entity Framework e dei Data Services