Spesso nelle nostre applicazioni, ci troviamo a dover eseguire operazioni a intervalli regolari, per esempio per verificare se un utente è ancora connesso, pulire il contenuto di una tabella o effettuare il polling su una risorsa.
Una possibile soluzione, se siamo su Azure, è quella di utilizzare una Function con time trigger, con la complessità però di avere un'ulteriore "moving part" nella nostra architettura.
Un'alternativa più semplice è sfruttare gli hosted service di ASP.NET Core, che vengono eseguiti in automatico dal runtime come processi di background.
Ciò che dobbiamo fare è realizzare una classe che implementi l'interfaccia IHostedService:
internal class MyTimedService : IHostedService, IDisposable { private Timer _timer; private ILogger<MyTimedService> _logger; public MyTimedService(ILogger<MyTimedService> logger) { _logger = logger ?? throw new ArgumentNullException("logger"); } public Task StartAsync(CancellationToken cancellationToken) { _timer = new Timer( async state => { try { cancellationToken.ThrowIfCancellationRequested(); // ... nostra logica qui ... } catch (Exception ex) { _logger.LogError(ex, "Failed to execute"); } }, state:null, dueTime:TimeSpan.Zero, // questo è il delay per la prima esecuzione period:TimeSpan.FromMinutes(1)); // ogni minuto return Task.CompletedTask; } public Task StopAsync(CancellationToken cancellationToken) { _timer.Change(Timeout.Infinite, Timeout.Infinite); return Task.CompletedTask; } public void Dispose() { _timer.Dispose(); } }
Questa interfaccia si compone di due metodi, StartAsync e StopAsync, che il runtime invocherà per avviare e arrestare le operazioni.
In StartAsync creiamo un oggetto timer con un delegate che conterrà la nostra logica, da ripetere - nell'esempio - ogni minuto.
Il codice è piuttosto semplice, tuttavia ci sono un paio di accorgimenti a cui dobbiamo prestare attenzione. Il primo è relativo all'esecuzione, che deve avvenire all'interno di un blocco Try...Catch. In caso contrario, un'eccezione nel task porterebbe al crash dell'intera applicazione.
Il secondo è l'uso del cancellation token, che viene impostanto nel caso in cui è stato richiesto lo shutdown dell'applicazione durante l'avvio del nostro servizio. Nel nostro esempio verifichiamo lo stato all'inizio di ogni iterazione, ma, in casi più complessi, è buona norma passarlo anche alle componenti che lo supportano, in modo da interrompere task potenzialmente lunghi, come una richiesta HTTP per esempio.
Nella fase di StopAsync, invece, ci limitiamo a impostare il timer a Infinite per disabilitarlo.
Ultima nota riguarda l'interfaccia IDisposable. Questo metodo viene tipicamente richiamato in fase di shutdown, ma è sempre buona norma invocare il Dispose delle risorse utilizzate (in questo caso il nostro oggetto Timer).
Per attivare questo componente, è sufficiente registrarlo nei servizi durante la fase di startup:
public void ConfigureServices(IServiceCollection services) { services.AddControllers(); services.AddHostedService<MyTimedService>(); }
In un prossimo script, vedremo come iniettare servizi nel nostro task, così da renderlo ancora più versatile.
Commenti
Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.
Approfondimenti
-
Creazione di plugin per Tailwind CSS: espandere le Funzionalità del Framework
-
Utilizzare un service principal per accedere a Azure Container Registry
-
Effettuare il log delle chiamate a function di GPT in ASP.NET Web API
-
Utilizzare Copilot con Azure Cosmos DB
-
Gestire liste di tipi semplici con Entity Framework Core
-
Aggiungere interattività lato server in Blazor 8
-
Creazione di plugin per Tailwind CSS: espandere le funzionalità del framework dinamicamente
-
Usare il colore CSS per migliorare lo stile della pagina
-
Definire stili a livello di libreria in Angular
-
Sfruttare GPT-4o realtime su Azure Open AI per conversazioni vocali
-
Applicare un filtro per recuperare alcune issue di GitHub
-
Utilizzare il trigger SQL con le Azure Function