Worker Service template in .NET Core 3.0

With ASP.NET Core 3.0 Preview 3 we have template for background processes like Windows services and Linux daemons. New project template is called Worker Service and this writing shows how it works and how to use it.

Creating worker service application

After downloading .NET Core 3.0 Preview 3 open Visual Studio 2019, create new ASP.NET Core web application and select Worker service as project type.

Worker Service template

NB! Currently Worker Service is located under ASP.NET Core web applications and the template uses web SDK. This will change in the future as the intent by development team is not to have any dependencies to other SDK-s by default.

Default .NET Core worker service

With default implementation of worker service we get two classes: Program and Worker. Program class is very straightforward and a little bit similar to what we have in web applications. The difference is that instead of startup class we have worker class and it is registered as a hosted service.

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureServices(services =>
            {
                services.AddHostedService<Worker>();
            });
}

To make things more interesting compare the code here with the one shown in my post Running ASP.NET Core application as Windows service.

Worker class is also very laconic. Interesting thing to notice is support for .NET Core dependency injection. Notice how logger is given as constructor argument of Worker class. The worker class we get when creating new worker service project writes out current time after every second.

public class Worker : BackgroundService
{
    private readonly ILogger<Worker> _logger;

    public Worker(ILogger<Worker> logger)
    {
        _logger = logger;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            _logger.LogInformation($"Worker running at: {DateTime.Now}");
            await Task.Delay(1000, stoppingToken);
        }
    }
}

Without any additional configuration changes we can run the application to see it work.

.NET Core worker service output

Background service class

Worker service class inherits from BackgroundService defined in Microsoft.Extensions.Hosting.Abstractions package. We can see that there are additional methods we can override: StartAsync(), StopAsync() and Dispose(). StartAsync() and StopAsync() are inherited from IHostedService interface.

public abstract class BackgroundService : IHostedService, IDisposable
{
    public virtual void Dispose();
    public virtual Task StartAsync(CancellationToken cancellationToken);
    public virtual Task StopAsync(CancellationToken cancellationToken);
    protected abstract Task ExecuteAsync(CancellationToken stoppingToken);
}

We can use StartAsync() method to initialize our worker service and StopAsync() to clean up when worker is closing. If worker made use of any disposable resources then these resources must be disposed in Dispose() method that is latest point for this.

Extending worker service

As I had sample code already open in Visual Studio then I thought to try out what happens when I override other methods of BackgroundService too and write time to log same way as it is done in ExecuteAsync() method.

public class Worker : BackgroundService
{
    private readonly ILogger<Worker> _logger;

    public Worker(ILogger<Worker> logger)
    {
        _logger = logger;
    }

    public override Task StartAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation($"Worker started at: {DateTime.Now}");

        return base.StartAsync(cancellationToken);
    }

    protected override Task ExecuteAsync(CancellationToken stoppingToken)
    {
        _logger.LogInformation($"Worker running at: {DateTime.Now}");

        return Task.CompletedTask;
    }

    public override Task StopAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation($"Worker stopped at: {DateTime.Now}");

        return base.StopAsync(cancellationToken);
    }

    public override void Dispose()
    {
        _logger.LogInformation($"Worker disposed at: {DateTime.Now}");

        base.Dispose();
    }
}

And here is the result of running our extended worker service. Take a close look to output.

Worker service events logged to console

We can see here all worker service methods called. Interesting thing to notice is that worker service is started before application starts and it’s stopped after application stops. It’s explained at official document Background tasks with hosted services in ASP.NET Core.

Project file

Just for interest I also checked out what’s inside project file. Well, nothing special, I want to say.

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>netcoreapp3.0</TargetFramework>
    <OutputType>Exe</OutputType>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.Extensions.Hosting" Version="3.0.0-preview3.19153.1" />
  </ItemGroup>
</Project>

There’s reference to netcoreapp3.0 and Microsoft.Extensions.Hosting NuGet package. So, no mysteries and surprises – everything is neat and clean.

Wrapping up

Worker service template is good addition to .NET Core and it’s good to see that process hosting gets more and more generalized in .NET Core. Same time we have still all powerful features like dependency injection available. Perhaps most interesting is to see how worker service will be used as Windows service and Linux daemon and how much work it is to use same codebase on both platforms. From ASP.NET Core 3.0 Preview 3 announcement we can read that samples by Microsoft are coming soon.

Gunnar Peipman

Gunnar Peipman is ASP.NET, Azure and SharePoint fan, Estonian Microsoft user group leader, blogger, conference speaker, teacher, and tech maniac. Since 2008 he is Microsoft MVP specialized on ASP.NET.

    12 thoughts on “Worker Service template in .NET Core 3.0

    • March 8, 2019 at 5:24 pm
      Permalink

      In your StopAsync method, you’re calling StartAsync… this will probably have unintended consequences ;)

      I didn’t know about the BackgroundService class, I was implementing the start/stop logic myself… Thanks for the tip!

    • March 8, 2019 at 11:49 pm
      Permalink

      I was wondering how to implement a daemon in linux considering all the interruptions commands and stuff… If all of that is transparent or do we need to code something special for linux daemons…

    • March 9, 2019 at 6:03 am
      Permalink

      I’m not yet sure how it will be with stable version of .NET Core 3.0. To make something work as system background service we need some integration points with operating system modules that run background processes. It means dependencies to native libraries. I hope .NET Core 3.0 comes out with generalizations where there is common way how background services are controlled and how we can communicate with external processes that can send commands to services. Let’s see what next previews put on the table.

    • March 11, 2019 at 4:54 pm
      Permalink

      Any comments on how to run this in Azure natively? Containers only for now?

    • March 12, 2019 at 8:07 am
      Permalink

      I think every service on Azure is okay where you can run console application. Over coming weeks Microsoft should publish some articles that provide technical details about how to run worker services as Windows service and Linux daemon. I think we should wait until this information is published.

    • March 12, 2019 at 12:47 pm
      Permalink

      What is the difference between .NET Core Generic Host App and this new worker-service?

    • March 24, 2019 at 1:36 pm
      Permalink

      You have Greats and useful posts, please implement something like a rating or “I like it” to leave positive feedback, i want to show you that i liked a specific post but i don’t want to write a comment

    • April 9, 2019 at 11:12 am
      Permalink

      Thank you Gunnar, great article. I’ve noticed that if an exception happens, for example, the background service dies but the host process keeps running. Any recommendations on how to recover in such cases?

    • May 18, 2019 at 11:58 pm
      Permalink

      Great Article!!! Thank you.
      I have a quick question. Can worker service be called from angular website while hosted as a windows service?

    • May 19, 2019 at 12:29 am
      Permalink

      If your worker process has HTTP server implemented then it is possible. Theoretically – I have not tried it yet – you should be able to host also ASP.NET Core web application as Windows service.

    Leave a Reply

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