Net Core 2.2 provides Web Host for hosting web applications and Generic Host that is suitable for hosting a wider array of host apps. In the .Net Core 3 Generic Host will replace Web Host.  Generic Host will be suitable for hosting any kind of app including web applications.

I looked at many examples but found that none showed the complete implementation of the Generic Host that is implemented to run as a console, Linux daemon, and Windows Service all in one application.

Here we will be looking at extending sample_service_hosting app to run it as a console app, windows service, or Linux daemon as well as making it self installable windows service.

.Net Core provides IHostBuilder interface to configure and create host builder. In case of a console app, host builder will run await RunConsoleAsync() function. To host and run our Generic Host as Windows Service we will need to use IApplicationLifetime to register Start and Stop events.

For hosting our Generic Host in Linux daemon we are going to inject IApplicationLifetime into main service and register and handle Start and Stop events.

There are several ways we could go to extend it to run as Windows Service, console app and Linux daemon. One way is to have a separate .Net Core project that will host our sample generic host service for each case or allow the program to accept command line variables that specify how to run the program. We will implement the command line arguments.

Command-line options:

  • -i    Install as Windows Service
  • -u  Uninstall Windows Service
  • -console Run as a console app
  • -daemon Run as Linux daemon service
  • -h  Show command line switch help

Let’s make Argument Parser

In order to parse the arguments passed to the application, we will implement an argument parser class, which will return HostAction enum that specifies how the application is going to start. The application will accept only one argument on its input. If more than one argument supplied or it is an invalid argument, it will show usage message. If no arguments supplied it will try to run as Windows Service.

HostAction enum

Argument Parser class – ArgsParser

Let’s make HostedService class

At the moment sample_service_hosting app creates host builder by calling CreateHostBuilder() from the Main function. We need to introduce a class that will perform an action depending on what HostAction returned by ArgsParser. We will call it HostedService class. It will have an async Run function that will start different action.

For now let’s implement run as a console, run as Linux daemon and show usage actions. Function CreateHostBuilder() will be moved from Program.cs to HostedService class.

HostedService class

In Program.cs we change code as follows.

Program.cs

Let’s Make it self installable Windows Service

Now we got to the point of making our sample app to run as Windows Service. As Software Developer we always try to make the life of our users easier. If the app will be able to self install/uninstall as windows service our users will be much happier than trying to do that themselves.

We will start in the external process sc.exe service controller tool with parameters to install/uninstall/stop service. Example:

  • sc.exe create “service_name” displayname= “service_name” binpath= “path to exe file”
  • sc.exe delete “service_name”
  • sc.exe stop “service_name”

WinServiceInstaller class will be responsible for running an external process and notifying of the progress. We will use WinService class to handle Start, Stop events and use extension functions to inject our WinService class into our Generic Host Builder.

WinService class

WinServiceInstaller class

WinServiceExtensions static class

We need to add to our project package reference System.ServiceProcess.ServiceController in order to compile WinService class.

Now in HostedService Run function, we can implement remaining switch cases that will Install, Uninstall and Run our app as windows service.

You may have noticed that APP_EXECUTABLE_PATH is set by calling utility function GetExecutingAssemblyLocation in Utility class.

Utility static class

Let’s update the Main function

As the final step, we will update our Program.cs and add the logger to print status of our Windows Service. At the end before closing application, we also need to Flush logger and shut it down to release resource when our app will run as Linux daemon.

Program.cs

Summary

Today we extended sample_service_hosting app with the ability to run as windows service and self install/uninstall itself to make it easier to deploy as windows service. We could go down the path of implementing separate projects: one for a console app, one for Linux daemon, one for windows service and one common project with our SampleService Host. We managed to do it all in one project with the use of ArgsParser class and extension functions to inject our Host into WinService.

Leave a comment

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