将ASP.NET Core托管为Windows服务

Mar*_*a P 31 c# windows-services .net-core asp.net-core

当我在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<Startup>()
      .Build();

      host.RunAsService();
    }

    protected override void OnStop() {}
  }
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

Iva*_*nov 52

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

使用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<Startup>()
            .Build();
    
        if (Debugger.IsAttached || args.Contains("--debug"))
        {
            host.Run();
        }
        else
        {
            host.RunAsService();
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

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

    sc create MyService binPath = "Full\Path\To\The\Console\file.exe"
Run Code Online (Sandbox Code Playgroud)

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

继承WebHostService

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

我们假设以下是继承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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

从前一个入口点示例中唯一要改变的行是最后的else语句,它必须调用正确的扩展方法

host.RunAsCustomService();
Run Code Online (Sandbox Code Playgroud)

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

sc create MyService binPath = "Full\Path\To\The\Console\file.exe"
Run Code Online (Sandbox Code Playgroud)


Mar*_*ich 9

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

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

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


Dmi*_*lov 5

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

public static void Main(string[] args)
{
    var host = new WebHostBuilder()
                .UseIISIntegration()
                .UseKestrel()
                .UseContentRoot(@"Path\To\Content\Root")
                .UseStartup<Startup>()
                .Build();

    if (Debugger.IsAttached || args.Contains("--debug"))
    {
        host.Run();
    }
    else
    {
        host.RunAsService();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

这篇文章“ 如何在Windows服务中托管ASP.NET Core”和注释涵盖了详细信息。

UPDATE(请参阅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<Startup>()
            .Build();

        host.Run();
    }
}
Run Code Online (Sandbox Code Playgroud)

在中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<Startup>()
            .Build();
}
Run Code Online (Sandbox Code Playgroud)

  • 很好的例子,但我认为你可能想要更改 host.RunAsService(); 行 到 host.RunAsMyService(); 所以它匹配扩展器 (2认同)

how*_*dlo 1

使用最新的 VS2015 Update 2 ASP.NET Core Web 应用程序 (.NET Framework) 模板和 Program.cs 的 mods,如下所示,它在作为服务、独立运行和在 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<Startup>()
            .Build();

        if (args.Contains("--windows-service"))
        {
            host = new WebHostBuilder()
            .UseKestrel()
            .UseContentRoot("<directory-containing-wwwroot>")
            .UseIISIntegration()
            .UseStartup<Startup>()
            .UseUrls("http://+:5000")
            .Build();

            Startup.is_service = true;
            host.RunAsService();
        }
        else
        {
            host.Run();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • sc.exe &lt;服务名称&gt; binPath= "&lt;服务exe 路径&gt; --windows-service"。因此提供 --windows-service 作为 binPath 的一部分 (2认同)
  • 我在“IWebHost”上没有“RunAsService” - 这是从哪里来的? (2认同)