托管ASP.NET Core作为Windows服务

当我在RC2中得到它时,支持在Windows服务中托管应用程序。 我试图在一个简单的web api项目上测试它(使用.NET Framework 4.6.1)。

这是我的Program.cs代码:

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() .Build(); host.RunAsService(); } protected override void OnStop() {} } } 

所有其他的东西基本上都来自.NET Core模板(虽然我将框架更改为net461并在project.json中添加了一些依赖项)。

在使用dotnet publish并使用sc create创建Windows服务后,我可以成功启动我的服务,但是我无法访问任何控制器(端口没有监听)。 我想我做错了什么。

所以我想主要的问题是如何制作自托管的web api并将其作为Windows服务运行。 RC2更新后,所有找到的解决方案都不起作用。

你有几个选择 – 使用Microsoft的WebHostService类,inheritanceWebHostService或编写自己的。 后者的原因是使用Microsoft的实现,我们不能使用inheritanceWebHostService的类型参数编写通用扩展方法,因为此类不包含无参数构造函数,也无法访问服务定位器。

使用WebHostService

在这个例子中,我将创建一个使用Microsoft.DotNet.Web.targets的控制台应用程序,输出.exe并作为MVC应用程序(视图,控制器等)运行。 我假设创建控制台应用程序,更改.xproj中的目标并修改project.json以获得正确的发布选项并从标准.NET Core Web应用程序模板复制视图,控制器和webroot是微不足道的。

现在必不可少的部分:

  1. 获取此包并确保project.json文件中的框架是net451(或更新版本)

  2. 确保入口点中的内容根目录已正确设置为应用程序.exe文件的发布目录,并且调用了RunAsService()扩展方法。 例如:

     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() .Build(); if (Debugger.IsAttached || args.Contains("--debug")) { host.Run(); } else { host.RunAsService(); } } 

现在可以使用以下命令轻松安装.exe

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

启动服务后,将托管Web应用程序并成功查找并呈现其视图。

inheritanceWebHostService

这种方法的一个主要好处是,它允许我们覆盖OnStopping,OnStarting和OnStarted方法。

我们假设以下是inheritanceWebHostService的自定义类

 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(); } } 

按照上面的步骤,我们必须写下我们自己的扩展方法,使用我们的自定义类运行主机:

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

从前一个入口点的例子中剩下要改变的唯一一行是最后的else语句,它必须调用适当的扩展方法

 host.RunAsCustomService(); 

最后,使用与上面相同的步骤安装服务。

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

如果可以仅在完整的.NET Framework上运行,那么之前的答案就足够了(inheritance自ServiceBase或使用Microsoft的WebHostService )。

但是,如果你想/只想在.NET Core上运行(例如在windows nano服务器上,单个二进制文件在linux上作为普通应用程序和windows上的服务工作,或者需要与应用程序并行运行旧的.NET Framework版本,所以你不能更新系统框架),你必须通过P / Invokes自己做适当的Windows API调用。 因为我必须这样做,所以我创建了一个完全正确的库 。

有一个可用的示例 ,当使用管理权限运行时也可以自行安装(例如dotnet MyService.dll --register-as-service )。

我在寻找类似问题的解决方案时找到了这个主题。 结束实现非常(非常)简化Topshelf的工作。 您可以轻松地作为控制台运行和/或安装,卸载等一项服务。 我认为这对某些人来说非常有用。 你可以在这里找到代码: https : //github.com/PeterKottas/DotNetCore.WindowsService以及这里的nuget以及https://www.nuget.org/packages/PeterKottas.DotNetCore.WindowsService/ 。 请享用 :)

使用Visual Studio 2017可以轻松创建Windows服务。您需要将.NET Core代码移动到以NetStandard为目标的类库,然后才能引用该类库。 您的Windows服务项目必须以完整的.NET Framework为目标,但可以引用您的共享库。

通过将所有代码放在类库中,您就可以在Windows服务和其他非Windows应用程序之间实现可移植性。

使用VS 2015,您无法创建Windows服务项目并引用.NET Core xproj。 Visual Studio 2017修复了将所有项目转换为csproj后的问题。

本博客详细介绍了它: 如何使用Visual Studio 2017创建.NET核心Windows服务

使用最新的VS2015 Update 2 ASP.NET核心Web应用程序(.NET Framework)模板以及如下所示的Program.cs的mod,它在作为服务运行时独立运行并且在VS中运行正常。 请注意,作为服务运行时,需要设置包含wwwroot的目录的路径。

到目前为止,我真的很喜欢这个模板和模式。 可以像往常一样在Visual Studio中开发MVC6代码,然后将其干净地部署为服务。 事实上,我注意到在部署服务的本地实例进行测试时,不需要使用sc.exe删除/创建服务。 只需停止服务,发布代码并重新启动服务,它就会获取新的更改。

 public class Program { public static void Main(string[] args) { IWebHost host = new WebHostBuilder() .UseKestrel() .UseContentRoot(Directory.GetCurrentDirectory()) .UseIISIntegration() .UseStartup() .Build(); if (args.Contains("--windows-service")) { host = new WebHostBuilder() .UseKestrel() .UseContentRoot("") .UseIISIntegration() .UseStartup() .UseUrls("http://+:5000") .Build(); Startup.is_service = true; host.RunAsService(); } else { host.Run(); } } } 

您需要引用Microsoft.AspNetCore.HostingMicrosoft.AspNetCore.Hosting.WindowsServices并在Startup类中使用此代码使其作为Windows服务运行:

 public static void Main(string[] args) { var host = new WebHostBuilder() .UseIISIntegration() .UseKestrel() .UseContentRoot(@"Path\To\Content\Root") .UseStartup() .Build(); if (Debugger.IsAttached || args.Contains("--debug")) { host.Run(); } else { host.RunAsService(); } } 

然后,您需要为IWebHost.RunAsService添加扩展方法,以使用OnStoppingOnStarting事件处理程序将其与自定义WebHostService类包装在一起:

 public static class MyWebHostServiceServiceExtensions { public static void RunAsMyService(this IWebHost host) { var webHostService = new MyWebHostService(host); ServiceBase.Run(webHostService); } } internal class MyWebHostService : WebHostService { public MyWebHostService(IWebHost host) : base(host) { } protected override void OnStarting(string[] args) { base.OnStarting(args); } protected override void OnStarted() { base.OnStarted(); } protected override void OnStopping() { base.OnStopping(); } } 

这篇文章如何在Windows服务中托管您的ASP.NET Core并且评论涵盖了详细信息。

更新 (请参阅ASP.NET Core 2.0中新增内容的快速摘要中的更多详细信息):

ASP.NET Core 1.1我们有这样的事情:

 public class Program { public static void Main(string[] args) { var host = new WebHostBuilder() .UseKestrel() .UseContentRoot(Directory.GetCurrentDirectory()) .UseIISIntegration() .UseStartup() .Build(); host.Run(); } } 

ASP.NET Core 2.0 ,它看起来像这样:

 public class Program { public static void Main(string[] args) { BuildWebHost(args).Run(); } public static IWebHost BuildWebHost(string[] args) => WebHost.CreateDefaultBuilder(args) .UseStartup() .Build(); } 

更新了我用于.netcore 2.1的内容,使用了尽可能多的库存模板,其中包括从appsettings.json读取配置,命令args,主机过滤等,在.netcore团队的帮助方法中实现。 因此,很多这些设置都是通过配置文件或命令args来控制的。 查看microsoft关于他库存模板提供的文档以及如何覆盖设置的文档。

请注意,如果您使用https和默认开发证书定义端点,我看到该服务无法启动。 可能只是指定pfx via配置。 如果有人想要改进这一点,请随意这样做。

无论如何这里是我在program.cs中使用的股票模板代码

 public class Program { public static void Main(string[] args) { if (args.Contains("--service")) { var path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); Directory.SetCurrentDirectory(path); // need this because WebHost.CreateDefaultBuilder queries current directory to look for config files and content root folder. service start up sets this to win32's folder. var host = CreateWebHostBuilder(args).Build(); host.RunAsService(); } else { CreateWebHostBuilder(args).Build().Run(); } } public static IWebHostBuilder CreateWebHostBuilder(string[] args) => WebHost.CreateDefaultBuilder(args) .UseStartup(); }