It is easy to implement Background tasks and scheduled work using IHostedService and the BackgroundService class.
Sometimes it is required certain work to be offloaded when a Web API request is processed. That work could be accessing database records and update some information on some tables based on existing data.
In this post, I’m going to show how to Implement background tasks using IHostedService and the BackgroundService class that is suggested by the MSDN article.
Also, I will cover how to access your scoped service from this background task. This way you can access the service to talk to your database to process some information.
From NET Core 2.1 and up, you can use named IHostedService that helps you to easily implement hosted services.
We will register the hosted service that runs in the background while your web host or host is running.
You have to register the hosted services within the familiar ConfigureServices()
method of the Startup
class, as in the following code from a typical ASP.NET WebHost.
public static void Main(string[] args) { CreateHostBuilder(args).Build().Run(); } public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); }) .ConfigureServices(services => { services.AddHostedService<StatusCheckerService>(); });
Use only one way to register from these two options.
public IServiceProvider ConfigureServices(IServiceCollection services) { //Other DI registrations; // Register Hosted Services services.AddHostedService<StatusCheckerService>(); services.AddHostedService<MyHostedServiceA>(); services.AddHostedService<MyHostedServiceB>(); //... }
Next is to use the Background base class (available only from dot net core 2.1)
////// Base class for implementing a long running public abstract class BackgroundService : IHostedService, IDisposable { private Task _executingTask; private readonly CancellationTokenSource _stoppingCts = new CancellationTokenSource(); protected abstract Task ExecuteAsync(CancellationToken stoppingToken); public virtual Task StartAsync(CancellationToken cancellationToken) { // Store the task we're executing _executingTask = ExecuteAsync(_stoppingCts.Token); // If the task is completed then return it, // this will bubble cancellation and failure to the caller if (_executingTask.IsCompleted) { return _executingTask; } // Otherwise it's running return Task.CompletedTask; } public virtual async Task StopAsync(CancellationToken cancellationToken) { // Stop called without start if (_executingTask == null) { return; } try { // Signal cancellation to the executing method _stoppingCts.Cancel(); } finally { // Wait until the task completes or the stop token triggers await Task.WhenAny(_executingTask, Task.Delay(Timeout.Infinite, cancellationToken)); } } public virtual void Dispose() { _stoppingCts.Cancel(); } }. ///
When deriving from the above abstract base class, you just need to implement the ExecuteAsync()
method in your own custom hosted service class as shown below.
using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using System; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace Services // your namespace where this class is placed { public class StatusCheckerService: BackgroundService { private readonly ILogger<StatusCheckerService> logger; public StatusCheckerService( ILogger<StatusCheckerService> logger, { this.logger = logger; } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { logger.LogDebug($"StatusCheckerService is starting."); stoppingToken.Register(() => logger.LogDebug($"StatusCheckerService background task is stopping.")); while (!stoppingToken.IsCancellationRequested) { // MyMethodOrLogic goes here. You may call any method inside this class. logger.LogDebug($"StatusCheckerService task doing background work."); await Task.Delay(5000, stoppingToken); // Time to pause this background logic } logger.LogDebug($"StatusCheckerService background task is stopping."); } } }
For more detailed information on this topic, refer to this post from the MSDN article. My intention in this post is to show you how to access scoped service in this background task and communicate with the database.
Now, you wonder how to access Scoped Service from this background task?
Using IServiceScopeFactory Interface. A factory for creating instances of IServiceScope, which is used to create services within a scope
Complete logic to access scoped service.
public class StatusCheckerService: BackgroundService { private readonly ILogger<StatusCheckerService> logger; private readonly IServiceScopeFactory serviceScopeFactory; public StatusCheckerService( ILogger<StatusCheckerService> logger,IServiceScopeFactory serviceScopeFactory) { this.logger = logger; this.serviceScopeFactory = serviceScopeFactory; } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { logger.LogDebug($"StatusCheckerService is starting."); stoppingToken.Register(() => logger.LogDebug($"StatusCheckerService background task is stopping.")); while (!stoppingToken.IsCancellationRequested) { using (var scope = serviceScopeFactory.CreateScope()) { // You can ask for any service here and DI will resolve it and give you back service instance var contextService = scope.ServiceProvider.GetRequiredService<IContextService&ht;(); contextService.YourMethodOrServiceMethod(); //access dbcontext or anything thats available form your service } logger.LogDebug($"StatusCheckerService task doing background work."); await Task.Delay(5000, stoppingToken); // Time to pause this background logic } logger.LogDebug($"StatusCheckerService background task is stopping."); } }
Related Posts
- Implement create, read, update, and delete functionalities using Entity Framework Core
- Working with optional body parameters in ASP.NET Core 2.2
- How to upload a file with .NET CORE Web API 3.1 using IFormFile
Conclusion
In this post, I showed how to Implement background tasks using IHostedService and the BackgroundService class and access scoped service. That’s all from this post. If you have any questions or just want to chat with me, feel free to leave a comment below
I was very pleased to discover this site. I want to to thank you for your
time just for this wonderful read!! I definitely appreciated every part of it and I
have you saved to fav to look at new things on your website.
This information is worth everyone’s attention. How
can I find out more?
Thank you for your post.Thanks Again. Awesome.
Good day I am so thrilled I found your blog page, I really found you by mistake, while I was browsing on Aol for something else, Regardless I am here now and would
just like to say many thanks for a fantastic post and a all
round enjoyable blog (I also love the theme/design), I don’t have time
to read it all at the moment but I have saved it and also added your RSS feeds, so when I have time
I will be back to read a great deal more, Please do keep up the superb jo.
I constantly emailed this webpage post page to all
my contacts, because if like to read it afterward
my friends will too.
Hi to all, it’s really a good for me to go to see this web site, it includes precious Information.