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"); }