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
Eseguire una GroupBy per entity in Entity Framework
Utilizzare l'operatore GroupBy come ultima istruzione di una query LINQ in Entity Framework
Supporto ai tipi DateOnly e TimeOnly in Entity Framework Core
Potenziare Azure AI Search con la ricerca vettoriale
Utilizzare la versione generica di EntityTypeConfiguration in Entity Framework Core
Miglioramenti nelle performance di Angular 16
Creare form tipizzati con Angular
Personalizzare l'errore del rate limiting middleware in ASP.NET Core
Eseguire query manipolando le liste contenute in un oggetto mappato verso una colonna JSON
Sfruttare lo stream rendering per le pagine statiche di Blazor 8
Limitare le richieste lato server con l'interactive routing di Blazor 8
Creazione di plugin per Tailwind CSS: espandere le funzionalità del framework dinamicamente
I più letti di oggi
- Microsoft annuncia Windows "TrustBridge"
- ecco tutte le novità pubblicate sui nostri siti questa settimana: https://aspit.co/wkly buon week-end!
- Estrarre dati randomici da una lista di oggetti in C#
- Configurare il nome della run di un workflow di GitHub in base al contesto di esecuzione
- Usare il colore CSS per migliorare lo stile della pagina