Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
167 views
in Technique[技术] by (71.8m points)

c# - 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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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 = "FullPathToTheConsolefile.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 = "FullPathToTheConsolefile.exe"

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...