You can use Hangfire It's a fantastic framework for background jobs in ASP.NET.You can find HangFie Tutorial Here.
The best feature from Hangfire is its built in /hangfire dashboard that shows you all your scheduled, processing, succeeded and failed jobs. It's really a nice polished addition.
All these libraries are excellent, are open source, and Available as Nuget Packages.

Some Other Options
QUARTZ.NET
FLUENTSCHEDULER
WEBBACKGROUNDER
Updated 03-2022, read it on the bottom!
Updated 04-2020, read it on the bottom!
@Panagiotis Kanavos gave an answer in the comments of my question but it did not post it as an actual answer; this answer is dedicated to him/her.
I used a Timed background service like the one from Microsoft docs to create the service.
internal class TimedHostedService : IHostedService, IDisposable
{
private readonly ILogger _logger;
private Timer _timer;
public TimedHostedService(ILogger<TimedHostedService> logger)
{
_logger = logger;
}
public Task StartAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Timed Background Service is starting.");
_timer = new Timer(DoWork, null, TimeSpan.Zero,
TimeSpan.FromSeconds(5));
return Task.CompletedTask;
}
private void DoWork(object state)
{
_logger.LogInformation("Timed Background Service is working.");
}
public Task StopAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Timed Background Service is stopping.");
_timer?.Change(Timeout.Infinite, 0);
return Task.CompletedTask;
}
public void Dispose()
{
_timer?.Dispose();
}
}
In my case I made the call async by doing _timer.new Timer(async () => await DoWorkAsync(), ...)
In the future, an extension could be written that makes a class like this available in the Extensions repo because I think this is quite useful. I posted the github issue link in the description.
A tip, if you plan on reusing this class for multiple hosted services, consider creating a base class that contains the timer and an abstract or something so the "time" logic is only in one place.PerformWork()
Thank you for your answers! I hope this helps someone in the future.
Update 04-2020:
Injecting a scoped service in here is not possible with the normal Core service collection DI container, out of the box. I was using autofac which made it possible to use scoped services like in the constructor because of wrong registration, but when I started working on a different project that used only IClassRepository we figured out that injecting scoped things do not work because you are not in a scoped context.AddScoped<>(), AddSingleton<>(), AddTransient<>()
In order to use your scoped services, inject a (Easier to test with) and use IServiceScopeFactory which allows you to use CreateScope() with a scope.GetService() statement :)using
Update 03-2022: This post has gotten LOTS of views and attention, but I have to say I am no longer a big fan of my solution. I would propose different solutions:
The downsides of the solution posted in this answer are:
async support in this solution. I never really figured out if this solution is "correct"Quartz.Net does support this.You have to read the sentence “Hosted service that activates a scoped service” within its full context:
This article provides three hosted service examples:
- Background task that runs on a timer.
- Hosted service that activates a scoped service. The scoped service can use dependency injection (DI).
- Queued background tasks that run sequentially.
(from “Background tasks with hosted services”, emphasis mine)
So it is not the case that hosted services have a scoped lifetime. All hosted services added using are actually added with a singleton lifetime, ensuring that there will only ever be a single instance of it.AddHostedService()
What the article refers to is the situation when you need to consume a scoped service, like a database connection, within a hosted service. Since you cannot inject scoped dependencies into a singleton service, you will need a different solution there. And the solution usually involves having the singleton service (the hosted service in this case) create a service scope itself from which it can then retrieve the scoped dependency.
I went into more details about the service scopes in this recent answer to a similar question if you are interested.