.NET Core Workers as Windows Services

Avatar

Glenn

In .NET Core 3.0 we are introducing a new type of application template called Worker Service. This template is intended to give you a starting point for writing long running services in .NET Core. In this walkthrough we will create a worker and run it as a Windows Service.

Create a worker

Preview Note: In our preview releases the worker template is in the same menu as the Web templates. This will change in a future release. We intend to place the Worker Service template directly inside the create new project wizard.

Create a Worker in Visual Studio

image

image

image

Create a Worker on the command line

Run dotnet new worker

image

Run as a Windows Service

In order to run as a Windows Service we need our worker to listen for start and stop signals from ServiceBase the .NET type that exposes the Windows Service systems to .NET applications. To do this we want to:

Add the Microsoft.Extensions.Hosting.WindowsServices NuGet package

image

Add the UseServiceBaseLifetime call to the HostBuilder in our Program.cs

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

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

This method does a couple of things. First, it checks whether or not the application is actually running as a Windows Service, if it isn’t then it noops which makes this method safe to be called when running locally or when running as a Windows Service. You don’t need to add guard clauses to it and can just run the app normally when not installed as a Windows Service.

Secondly, it configures your host to use a ServiceBaseLifetime. ServiceBaseLifetime works with ServiceBase to help control the lifetime of your app when run as a Windows Service. This overrides the default ConsoleLifetime that handles signals like CTL+C.

Install the Worker

Once we have our worker using the ServiceBaseLifetime we then need to install it:

First, lets publish the application. We will install the Windows Service in-place, meaning the exe will be locked whenever the service is running. The publish step is a nice way to make sure all the files I need to run the service are in one place and ready to be installed.

dotnet publish -o c:\code\workerpub

Then we can use the sc utility in an admin command prompt

sc create workertest binPath=c:\code\workerpub\WorkerTest.exe

For example:

image

Security note: This command has the service run as local system, which isn’t something you will generally want to do. Instead you should create a service account and run the windows service as that account. We will not talk about that here, but there is some documentation on the ASP.NET docs talking about it here: https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/windows-service?view=aspnetcore-2.2

Logging

The logging system has an Event Log provider that can send log message directly to the Windows Event Log. To log to the event log you can add the Microsoft.Extensions.Logging.EventLog package and then modify your Program.cs:

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

Future Work

In upcoming previews we plan to improve the experience of using Workers with Windows Services by:

  1. Rename UseWindowsServiceBaseLifetime to UseWindowsService
  2. Add automatic and improved integration with the Event Log when running as a Windows Service.

Conclusion

We hope you try out this new template and want you to let us know how it goes, you can file any bugs or suggestions here.

Avatar
Glenn Condron

Follow Glenn   

20 Comments
Avatar
Renze Torensma 2019-03-29 12:58:28
Can you explain the difference between the Service workers in 3.0 and IHostedService in 2.x?
Gregory Suvalian
Gregory Suvalian 2019-03-29 13:31:36
What is the story for UNIX (configure to run app as daemon)
Avatar
Andrei Mironov 2019-03-29 15:21:41
Could I use logging to Application Insights instead of Event Log?
Avatar
R wing 2019-03-30 03:55:28
"We intend to place the Worker Server template directly inside the create new project wizard."maybe is typo : Worker Server -> Worker Service
David McClelland
David McClelland 2019-04-01 06:41:50
This is great!  Is there a way to detect (with the Microsoft.Extensions.Hosting.WindowsServices NuGet package) that my application is running as a Windows Service vs running as a console app?  When my code is running as a Windows Service, I want to do certain things - but if I'm just running the EXE from the command line I'd like it to do other things. I have seen this approach used, but is requires an extra command line parameter:  https://github.com/stevejgordon/IHostedServiceAsAService/blob/de55562bb1e424973660892e71b67a6c8200bfc3/IHostedServiceAsAService/Program.cs#L11-L29 And I saw this in Microsoft.Extensions.Hosting.WindowsServices, but it's private:  https://github.com/aspnet/Extensions/blob/898f0947fa4271d08e88daea503be6fd8ffb3c4f/src/Hosting/WindowsServices/src/WindowsServiceLifetimeHostBuilderExtensions.cs#L54-L67
Avatar
James Chaldecott 2019-04-08 10:46:40
I'm a little confused. Is this an ASP.Net Core specific thing, or for .Net Core 3.0 in general? Is it of any use without ASP.Net? How does it compare to TopShelf?
Admir Hodzic
Admir Hodzic 2019-04-09 14:57:47
Can this template be used to devlop MVC Core app, so we can join Windows Service and Mvc app in once to deploy it whitout IIS 
Artur Teregulov
Artur Teregulov 2019-04-10 03:54:25
Information about Linux is much more needed.
Avatar
比 波 2019-04-10 18:23:08
收藏
Avatar
Tomasz Jagusz 2019-04-11 01:43:33
Please consider adding an option to override PreshutdownTimeout and/or to extend ServiceBase and ServiceInstaller and use those classes. Currently, I have my own base class that allows me to extend preshutdown timeout, because I want the current operation to finish before I shut down service. Having the ability to extend (override) the default preshutdown timeout would be awesome!
Avatar
anonymous 2019-04-16 06:08:27
This comment has been deleted.
Avatar
Naveed Butt 2019-04-25 00:22:51
Since this blog post was pre VS 2019 release, I assume that every thing worked well on VS 2019 RC. Now I have installed VS 2019 Enterprise, why do I need to install RC as well, just to play around with .Net Core 3.0 features? Maybe this question is not suitable for this blog post, but I couldn't find a suitable place for the question... 
King David Consulting LLC
King David Consulting LLC 2019-06-11 12:37:09
I just updated to `https://github.com/kdcllc/CronScheduler.AspNetCore/` to support Worker cron scheduled jobs to be executed inside the console.
Avatar
Daniel Carvalho Liedke 2019-06-28 07:03:43
Hello, using preview6, after creating a new worker project without any code change, when I try to start the service it times out. How can I get this fixed? Thanks, Daniel 
Erik Parso
Erik Parso 2019-07-22 08:17:12
Is there a way desktop client can communicate with service ? 
Avatar
Michael T. DePouw Spottedmahn 2019-07-22 13:30:08
I tried creating a new worker service project but it doesn't build 😢 Developer Community Issue