.NET Core Workers as Windows Services
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
Create a Worker on the command line
Run dotnet new worker
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
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:
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:
- Rename UseWindowsServiceBaseLifetime to UseWindowsService
- 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.
33 comments
Can you explain the difference between the Service workers in 3.0 and IHostedService in 2.x?
They are the same thing. 3.0 adds a template and refinements but the BackgroundService you get in the worker template is an IHostedService that we’ve made where you just do the work you want instead of implementing start/stop. This is the progression of those features :).
What is the story for UNIX (configure to run app as daemon)
I plan to do a post about that next, short story is that with something like systemd you create a service config file and it runs fine. But there are a bunch of interesting details to dig into.
I’d also love to see that! Looking forward to it.
https://devblogs.microsoft.com/dotnet/net-core-and-systemd/
Could I use logging to Application Insights instead of Event Log?
You should be able to, the logging is exactly the same system as in ASP.NET Core applications just without the request/response parts. But I haven’t tried it yet. I should have. So I will go do that and report back.
You should be able to use this fine: https://www.nuget.org/packages/Microsoft.Extensions.Logging.ApplicationInsights/ and it will send logs to App Insights instead of the logger the same way I talked about here. I wasn’t sure it was decoupled from the other ASP.NET specific stuff. But it looks like it is :).
“We intend to place the Worker Server template directly inside the create new project wizard.”maybe is typo : Worker Server -> Worker Service
Thanks, fixed :).
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-L67Hi David, this got put in a moderation queue, presumably because of the links. I saw that you created a GitHub issue for it so I will talk more there. Thanks 🙂
No problemo – here’s the link to the GitHub issue (more of a feature request) in case anyone else has feedback: https://github.com/aspnet/Extensions/issues/1337
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?
TopShelf doesn’t work with .NET Core but .NET Framework. So if you want to target .NET Core, Worker can be a great solution.
+1 on ASP.Net Core project selection question. Does it add ASP.Net dependencies (e.g. Kestrel) to the project? Or rather – why not use the new Microsoft.Extensions.Hosting.WindowsServices in the console app project type to run as a Windows service?
> 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.
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
Yes, the windows service support is tied to the generic host so it can be used to run any type of application (including ASP.NET Core applications).
Information about Linux is much more needed.
收藏
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!