Background services with IHostedService

I would like to present how to make background services in asp.net core with IHostedService.

What is IHostedService

You can use IHostedService to create background tasks in asp.net core projects. I used Quartz.NET to similar purposes in the past. I do not want to compare them because it is not purpose of this article :-). So, if you want to create background task you can do that by implementing IHostedService. It’s very simple 🙂

How can we use it

I would like to create very very simple background task which creates GUIDs every 10 seconds and save them in memory cache. Don’t worry I’ll display them on website 😉 We need to create some base class BackgroundService. I create something similar like BackgroundService from here

BackgroundService:

using Microsoft.Extensions.Hosting;
using System;
using System.Threading;
using System.Threading.Tasks;

namespace Letys.HostedService.Example.Services
{
  public abstract class BackgroundService : IHostedService, IDisposable
  {
    private Task task;
    private readonly CancellationTokenSource cancellationTokens = new CancellationTokenSource();

    protected abstract Task ExecuteAsync(CancellationToken stoppingToken);
    
    public virtual Task StartAsync(CancellationToken cancellationToken)
    {
      this.task = this.ExecuteAsync(this.cancellationTokens.Token);
      return this.task.IsCompleted ? this.task : Task.CompletedTask;
    }

    public virtual async Task StopAsync(CancellationToken cancellationToken)
    {
      if (this.task != null)
      {
        try
        {
          this.cancellationTokens.Cancel();
        }
        finally
        {
          await Task.WhenAny(task, Task.Delay(Timeout.Infinite, cancellationToken));
        }
      }
    }

    public virtual void Dispose()
    {
      this.cancellationTokens.Cancel();
    }
  }
}

After that we can create our background task class – ExampleGuidService:

using Letys.HostedService.Example.Models;
using Microsoft.Extensions.Caching.Memory;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace Letys.HostedService.Example.Services
{
  public class ExampleGuidService : BackgroundService
  {
    public const string ExampleGuidsKey = "ExampleGuids";
    private IMemoryCache memoryCache;

    public ExampleGuidService(IMemoryCache memoryCache)
    {
      this.memoryCache = memoryCache;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
      while (!stoppingToken.IsCancellationRequested)
      {
        GenerateNewExampleGuid();
        await Task.Delay(1000*10, stoppingToken);
      }
    }

    private void GenerateNewExampleGuid()
    {
      ExampleGuid example = new ExampleGuid
      {
        Timestamp = DateTime.Now,
        Guid = Guid.NewGuid()
      };

      var cacheEntryOptions = new MemoryCacheEntryOptions()
                                    .SetSlidingExpiration(TimeSpan.FromHours(24));

      if (!this.memoryCache.TryGetValue(ExampleGuidService.ExampleGuidsKey, out List<ExampleGuid> cacheEntry))
      {
        cacheEntry = new List<ExampleGuid>();                
      }

      cacheEntry.Add(example);
      this.memoryCache.Set(ExampleGuidService.ExampleGuidsKey, cacheEntry, cacheEntryOptions);
    }
  }
}

This is our ExampleGuid:

using System;

namespace Letys.HostedService.Example.Models
{
  public class ExampleGuid
  {
    public Guid Guid { get; set; }
    public DateTime Timestamp { get; set; }
  }
}

We can register ExampleGuidService in Startup.cs:

public void ConfigureServices(IServiceCollection services)
{
  services.AddMemoryCache();
  services.AddMvc();
  services.AddSingleton<IHostedService, ExampleGuidService>();
}

Now we can add ExampleGuids action and view:

public IActionResult ExampleGuids()
{
  if (!this.memoryCache.TryGetValue(ExampleGuidService.ExampleGuidsKey, out List cacheEntry))
  {
    cacheEntry = new List();
  }
  return View(cacheEntry);
}

 

@model IEnumerable<Letys.HostedService.Example.Models.ExampleGuid>

@{
  ViewData["Title"] = "ExampleGuids";
  Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>ExampleGuids</h2>

<p>
  <a asp-action="Create">Create New</a>
</p>
<table class="table">
  <thead>
    <tr>
      <th>@Html.DisplayNameFor(model => model.Guid)</th>
      <th>@Html.DisplayNameFor(model => model.Timestamp)</th>
    </tr>
  </thead>
  <tbody>
  @foreach (var item in Model) {
    <tr>
      <td>@Html.DisplayFor(modelItem => item.Guid)</td>
      <td>@Html.DisplayFor(modelItem => item.Timestamp)</td>
    </tr>
  }
  </tbody>
</table>

As you can see every 10 seconds ExampleGuidService creates new guid.

Useful links

Implementing background tasks in .NET Core 2.x webapps or microservices with IHostedService and the BackgroundService class

Implementing IHostedService in ASP.NET Core 2.0

Leave a Reply

Your email address will not be published. Required fields are marked *