Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hosting ASP.NET Core as Windows service

As I get it in RC2 there's a support for hosting applications within Windows Services. I tried to test it on a simple web api project (using .NET Framework 4.6.1).

Here's my Program.cs code:

using System; using System.IO; using System.Linq; using System.ServiceProcess; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting.WindowsServices;  namespace WebApplication4 {   public class Program : ServiceBase   {     public static void Main(string[] args)     {       if (args.Contains("--windows-service"))       {         Run(new Program());         return;       }        var program = new Program();       program.OnStart(null);       Console.ReadLine();       program.OnStop();     }      protected override void OnStart(string[] args)     {       var host = new WebHostBuilder()       .UseKestrel()       .UseContentRoot(Directory.GetCurrentDirectory())             .UseStartup<Startup>()       .Build();        host.RunAsService();     }      protected override void OnStop() {}   } } 

All the other stuff are basically from .NET Core template (though I changed framework to net461 and added some dependencies in project.json).

After publishing it with dotnet publish and creating Windows Service with sc create I can succesfully start my service, but I can't reach any of my controllers (ports are not listeting). I assume I'm doing something wrong.

So I guess the main question is how to make self hosted web api and run it as Windows Service. All found solutions don't work after RC2 update.

like image 299
Maria P Avatar asked May 20 '16 12:05

Maria P


People also ask

Does .NET Core support Windows Service?

NET Core and . NET 5+, developers who relied on . NET Framework could create Windows Services to perform background tasks or execute long-running processes. This functionality is still available and you can create Worker Services that run as a Windows Service.


2 Answers

You've got a couple of options here - use Microsoft's WebHostService class, inherit WebHostService or write your own. The reason for the latter being that using Microsoft's implementation, we cannot write a generic extension method with a type parameter inheriting WebHostService since this class does not contain a parameterless constructor nor can we access the service locator.

Using WebHostService

In this example, I'm going to create a Console Application that uses Microsoft.DotNet.Web.targets, outputs an .exe and operates as a MVC app (Views, Controllers, etc). I assume that creating the Console Application, changing the targets in the .xproj and modifying the project.json to have proper publish options and copying the Views, Controllers and webroot from the standard .NET Core web app template - is trivial.

Now the essential part:

  1. Get this package and make sure your framework in project.json file is net451 (or newer)

  2. Make sure the content root in the entry point is properly set to the publish directory of the application .exe file and that the RunAsService() extension method is called. E.g:

    public static void Main(string[] args) {     var exePath= System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName;     var directoryPath = Path.GetDirectoryName(exePath);      var host = new WebHostBuilder()         .UseKestrel()         .UseContentRoot(directoryPath)         .UseStartup<Startup>()         .Build();      if (Debugger.IsAttached || args.Contains("--debug"))     {         host.Run();     }     else     {         host.RunAsService();     } } 

The .exe can now easily be installed using the following command

    sc create MyService binPath = "Full\Path\To\The\Console\file.exe" 

Once the service is started, the web application is hosted and successfully finds and renders its Views.

Inherit WebHostService

One major benefit of this approach is that this lets us override the OnStopping, OnStarting and OnStarted methods.

Let's assume that the following is our custom class that inherits WebHostService

internal class CustomWebHostService : WebHostService {     public CustomWebHostService(IWebHost host) : base(host)     {     }      protected override void OnStarting(string[] args)     {         // Log         base.OnStarting(args);     }      protected override void OnStarted()     {         // More log         base.OnStarted();     }      protected override void OnStopping()     {         // Even more log         base.OnStopping();     } } 

Following the steps above, we have to write down our own extension method that runs the host using our custom class:

public static class CustomWebHostWindowsServiceExtensions {     public static void RunAsCustomService(this IWebHost host)     {         var webHostService = new CustomWebHostService(host);         ServiceBase.Run(webHostService);     } } 

The only line that remains to be changed from the previous example of the entry point is the else statement in the end, it has to call the proper extension method

host.RunAsCustomService(); 

Finally, installing the service using the same steps as above.

sc create MyService binPath = "Full\Path\To\The\Console\file.exe" 
like image 173
Ivan Prodanov Avatar answered Sep 18 '22 01:09

Ivan Prodanov


If it is okay to run on full .NET Framework only, the previous answers are sufficient (Inheriting from ServiceBase or using Microsoft's WebHostService).

If, however, you have / want to run on .NET Core only (e.g. on windows nano server, single binary that works on linux as normal app and as service on windows, or need to run side-by-side with apps on an old .NET Framework version so you can't update the system framework), you'd have to make the appropriate windows API calls yourself via P/Invokes. Since i had to do that, i created a library that does exactly that.

There is a sample available that is also able to install itself when run with administrative privileges (e.g. dotnet MyService.dll --register-as-service).

like image 28
Martin Ullrich Avatar answered Sep 17 '22 01:09

Martin Ullrich