Desde o ASP clássico nós temos um arquivo chamado Global.asa. Com o ASP.NET, este arquivo foi renomeado para Global.asax. A finalidade deste arquivo é fornecer uma forma de interceptar eventos que ocorrem no nível da aplicação. Entre estes eventos, nós temos um que é disparado indicando que a aplicação foi inicializada, outro que algum erro não tratado aconteceu, que uma nova requisição chegou, que a aplicação está sendo encerrada, etc.
Este arquivo já não existe mais no ASP.NET Core, porém a necessidade ainda existe em alguns tipos de aplicação. Para interceptar a inicialização da aplicação e o término dela, podemos recorrer à interface IApplicationLifetime. Esta interface fornece três propriedades que indica a inicialização da aplicação (ApplicationStarted), que ela está sendo encerrada (ApplicationStopping) e depois de encerrada (ApplicationStopped). Essas propriedades são do tipo CancellationToken, e através de um delegate do tipo Action, passamos para o método Register o código customizado que queremos executar quando estes eventos acontecerem.
Para exemplificar o uso e utilidade desta interface, considere o exemplo abaixo onde temos uma classe estática que gerencia o agendamento e execução de tarefas pelo Quartz.NET. Além do método Schedule, temos os métodos Start e Stop, que como já podemos perceber, queremos invocar cada um deles no início e no fim da aplicação.
public class TaskManager
{
public static void Start()
{
Scheduler = StdSchedulerFactory.GetDefaultScheduler().Result;
Scheduler.Start();
}
private static IScheduler Scheduler { get; set; }
public async static Task Schedule<TJob>(IDictionary data) where TJob : IJob
{
await Scheduler.ScheduleJob(
JobBuilder
.Create<TJob>()
.SetJobData(new JobDataMap(data))
.Build(),
TriggerBuilder
.Create()
.WithSimpleSchedule(x => x.WithRepeatCount(0))
.Build());
}
public static void Shutdown()
{
Scheduler?.Shutdown(true);
}
}
O método Start deverá ser chamado quando a aplicação estiver sendo inicializada. Já no momento, do encerramento, recorremos ao método Shutdown do Schedule, passando o parâmetro true, que indica que antes de encerrar o gerenciador de tarefas, é necessário aguardar o término de alguma que, eventualmente, ainda esteja em execução. A interface IApplicationLifetime, assim como diversas outras do ASP.NET Core, o próprio runtime cria a instância de uma implementação padrão e passa para o método Configure da nossa classe Startup. Com isso, basta associarmos os métodos aos respectivos eventos, conforme é possível visualizar abaixo:
public void Configure(
IApplicationBuilder app,
IHostingEnvironment env,
ILoggerFactory log,
IApplicationLifetime lifetime)
{
lifetime.ApplicationStarted.Register(() => TaskManager.Start());
lifetime.ApplicationStopped.Register(() => TaskManager.Shutdown());
//outras configurações
}
Por fim, a aplicação (os controllers) interagem com a classe TaskManager a partir do método Schedule<TJob>, indicando qual a tarefa que precisa ser executada e parâmetros contextuais que queremos passar para a implementação da mesma.
[HttpPost]
public async Task<IActionResult> AgendarExecucao()
{
await TaskManager
.Schedule<GeracaoDeDados>(
Request.Form.ToDictionary(x => x.Key, x => x.Value.ToString()));
return View("ExecucaoAgendada");
}