public async Task DoWork(CancellationToken cancellationToken)
{
var scope = serviceScopeFactory.CreateScope();
var context = scope.ServiceProvider.GetService<ApplicationDbContext>();
while (!cancellationToken.IsCancellationRequested)
{
foreach(var x in context.Students.ToList())
{
x.Class ++;
context.Students.Update(x);
}
context.SaveChanges();
await Task.Delay(1000);
}
}
I want to increase class of student By 1 every year. I want to execute this method automatically every new year,
Please refer to my reply in this thread: How to trigger .NET Core 3.1 Hosted Service at certain time?
If you want to implement scheduled tasks, I suggest you could also try to use the Cronos package and the Cron Expressions to configure the scheduled task (reference: link).
The Cronos package is a lightweight but full-fledged library for parsing cron expressions and calculating next occurrences with time zones and daylight saving time in mind. The Cronos is an open source project sponsored by HangfireIO, and you can read detailed documentation from its GitHub repository. The details steps as below:
Install the Cronos package via NuGet.
Create a CronJobService service with the following code:
public abstract class CronJobService : IHostedService, IDisposable
{
private System.Timers.Timer _timer;
private readonly CronExpression _expression;
private readonly TimeZoneInfo _timeZoneInfo;
protected CronJobService(string cronExpression, TimeZoneInfo timeZoneInfo)
{
_expression = CronExpression.Parse(cronExpression);
_timeZoneInfo = timeZoneInfo;
}
public virtual async Task StartAsync(CancellationToken cancellationToken)
{
await ScheduleJob(cancellationToken);
}
protected virtual async Task ScheduleJob(CancellationToken cancellationToken)
{
var next = _expression.GetNextOccurrence(DateTimeOffset.Now, _timeZoneInfo);
if (next.HasValue)
{
var delay = next.Value - DateTimeOffset.Now;
if (delay.TotalMilliseconds <= 0) // prevent non-positive values from being passed into Timer
{
await ScheduleJob(cancellationToken);
}
_timer = new System.Timers.Timer(delay.TotalMilliseconds);
_timer.Elapsed += async (sender, args) =>
{
_timer.Dispose(); // reset and dispose timer
_timer = null;
if (!cancellationToken.IsCancellationRequested)
{
await DoWork(cancellationToken);
}
if (!cancellationToken.IsCancellationRequested)
{
await ScheduleJob(cancellationToken); // reschedule next
}
};
_timer.Start();
}
await Task.CompletedTask;
}
public virtual async Task DoWork(CancellationToken cancellationToken)
{
await Task.Delay(5000, cancellationToken); // do the work
}
public virtual async Task StopAsync(CancellationToken cancellationToken)
{
_timer?.Stop();
await Task.CompletedTask;
}
public virtual void Dispose()
{
_timer?.Dispose();
}
}
public interface IScheduleConfig<T>
{
string CronExpression { get; set; }
TimeZoneInfo TimeZoneInfo { get; set; }
}
public class ScheduleConfig<T> : IScheduleConfig<T>
{
public string CronExpression { get; set; }
public TimeZoneInfo TimeZoneInfo { get; set; }
}
public static class ScheduledServiceExtensions
{
public static IServiceCollection AddCronJob<T>(this IServiceCollection services, Action<IScheduleConfig<T>> options) where T : CronJobService
{
if (options == null)
{
throw new ArgumentNullException(nameof(options), @"Please provide Schedule Configurations.");
}
var config = new ScheduleConfig<T>();
options.Invoke(config);
if (string.IsNullOrWhiteSpace(config.CronExpression))
{
throw new ArgumentNullException(nameof(ScheduleConfig<T>.CronExpression), @"Empty Cron Expression is not allowed.");
}
services.AddSingleton<IScheduleConfig<T>>(config);
services.AddHostedService<T>();
return services;
}
}
create a ScheduleJob.cs:
public class ScheduleJob: CronJobService
{
private readonly ILogger<ScheduleJob> _logger;
public ScheduleJob(IScheduleConfig<ScheduleJob> config, ILogger<ScheduleJob> logger)
: base(config.CronExpression, config.TimeZoneInfo)
{
_logger = logger;
}
public override Task StartAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("ScheduleJob starts.");
return base.StartAsync(cancellationToken);
}
public override Task DoWork(CancellationToken cancellationToken)
{
_logger.LogInformation($"{DateTime.Now:hh:mm:ss} ScheduleJob is working.");
return Task.CompletedTask;
}
public override Task StopAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("ScheduleJob is stopping.");
return base.StopAsync(cancellationToken);
}
}
Register the ScheduleJob service in the ConfigureServices method.
public void ConfigureServices(IServiceCollection services)
{
services.AddHostedService<HelloWorldHostedService>();
services.AddCronJob<ScheduleJob>(c=>
{
c.TimeZoneInfo = TimeZoneInfo.Local;
c.CronExpression = @"25 21 * * *"; // 21:25 PM daily.
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
Then the result as below:
In the above sample, it will run the Schedule Job at 21:25 PM daily. You can change the CronExpression to 0 0 1 1 *
, then, the job will run once a year at midnight of 1 January.