2017-10-04 132 views
9

我试图在.Net Core 2.0中构建一个Windows服务,但是我一直在墙上敲打我的头一整天并没有任何进展。 一切似乎都可以用核1.0/1.1,即使微软文档:.Net Core 2.0 Windows服务

Host an ASP.NET Core app in a Windows Service

TopShelf不支持2.0为好,因为我已经看到了。

我见过一些奇怪的解决方案,将所有的代码放在.Net标准类库中,然后使用.Net框架应用程序来承载Windows服务,但这在我看来并不优雅, m试图摆脱.Net框架。

我现在想要做甚么?我错过了一些非常基本的东西?

+0

[Windows服务与.NET核心]可能的重复(https://stackoverflow.com/questions/41014513/windows-service-with-net-core) –

+0

'试图摆脱.Net框架干脆'试图建立一个_Windows_服务可能是一场艰苦的战斗.. – thisextendsthat

回答

2

仅仅因为对基于.NET的Windows服务的支持驻留在.NET Framework中,您不能。

每引用您的文档:

先决条件

  • 应用程序必须在.NET框架运行时运行。

一个直接的原因是,该服务使用Microsoft.AspNetCore.Hosting.WindowsServices软件包,它依赖于.NET框架本身。

+0

你有什么要说的这个https://github.com/dasMulli/dotnet-win32-service – DGaspar

+0

它可以在Windows 64上正常工作吗? –

+0

@maxman当我测试它时,它与.net Core 2.0不兼容,所以我不得不使用https://github.com/PeterKottas/DotNetCore.WindowsService – DGaspar

5

我总结的一些选项:

  1. 移动你的代码到.NET标准库,并在.NET框架应用主机,所以你可以使用ServiceBase。这当然需要在目标机器上安装.NET Framework
  2. 使用NSSM(非吸入服务管理器)来管理.NET Core控制台应用程序(它具有公共域许可证)
  3. 使用Windows API调用挂钩到Windows服务方法。这是DotNetCore.WindowsServicedotnet-win32-service(都是MIT许可)所采取的做法

我觉得@ JeroenMostert的评论是有点苛刻 - 我可以看到不依赖于特定的.NET Framework版本上是可用的吸引力目标机器。其他人显然也有同样的感受,因为我所链接的2个回购渠道相当受欢迎。

+0

我删除了我的评论。我还写了一个新的答案,指出现在有一个基于MS的.NET Core 2.0服务解决方案(尽管使用一些第三方解决方案仍然更方便)。我相信这能舒缓任何刺耳的情绪。 :-) –

0

也许这是一个完整的cop-out,但请记住,如果有更多的docker支持,您可以构建一个在容器中运行的服务。在那一点上,它仍然是.net核心(2.0),但在你的Windows机器上运行。更重要的是,你可以在将来任何地方部署。

随着dotnet核心的成熟,我认为这是一个更好更好的解决方案,假设您的服务不需要本地主机的资源。

1

现在可以在没有第三方库的情况下使用.NET Core 2.0编写Windows服务,这要归功于Windows Compatibility Pack的发布(在撰写本文时,仍处于预发布阶段)。正如页面本身警告的那样:

但是在你开始移植之前,你应该明白你想用 完成迁移。只是移植到.NET Core,因为它是 新的.NET实现并不是一个很好的理由(除非你是一个真正的粉丝)。

特别是,在.NET核心编写Windows服务现在是可能的,但你不会得到跨平台兼容性,开箱即用,因为Windows以外平台上的组件将只是抛出一个PlatformNotSupportedException如果您尝试使用服务代码。可以解决这个问题(例如使用RuntimeInformation.IsOSPlatform),但这完全是另一个问题。

另外,第三方库在安装服务方面仍然可以提供更好的接口:从编写起,当前版本的兼容包(2.0.0-preview1-26216-02)不支持System.Configuration.Install命名空间,因此缺省方法ServiceProcessInstaller类和installutil将不起作用。稍后更多。我们假设您已经从项目模板中创建了一个全新的Windows服务(Service1)(由于它不包含任何有趣的内容,除了继承自ServiceBase的类以外没有任何其他内容),所以我们假设您已经创建了一个全新的Windows服务(Service1)。所有你需要做的,使之建立在.NET核2.0是编辑和使用新的格式替换.csproj

<Project Sdk="Microsoft.NET.Sdk" ToolsVersion="15.0"> 
    <PropertyGroup> 
    <OutputType>Exe</OutputType> 
    <TargetFramework>netcoreapp20</TargetFramework> 
    <RuntimeIdentifier>win-x64</RuntimeIdentifier> 
    </PropertyGroup> 
    <ItemGroup> 
    <PackageReference Include="Microsoft.Windows.Compatibility" Version="2.0.0-*" /> 
    </ItemGroup> 
</Project> 

,然后删除properties\AssemblyInfo.cs因为它不再需要将与版本信息发生冲突项目本身。

如果您已经有服务并且具有相关性,转换可能会更复杂。请参阅here

现在你应该可以运行dotnet publish并获得一个可执行文件。如上所述,您不能使用ServiceProcessInstaller类来安装该服务,因此您必须手动输入

  • 注册服务使用的事件源;
  • 创建实际的服务。

这可以通过一些PowerShell完成。从提升的提示中包含您发布的可执行文件的位置:

$messageResourceFile = "C:\Windows\Microsoft.NET\Framework64\v4.0.30319\EventLogMessages.dll" 
New-EventLog -LogName Application -Source Service1 -MessageResourceFile $messageResourceFile 
sc.exe create Service1 binPath= (Resolve-Path .\WindowsService1.exe) 

这不是在几个方面的理想:这个硬编码的消息资源文件的路径(我们真的应该确定它在哪里来自注册表中的可执行文件路径和运行时路径),并对服务名称和可执行文件名称进行硬编码。您可能希望通过在Program.cs中执行一些命令行解析来为您的项目提供自己的安装功能,或使用Cocowalla's answer中提到的其中一个库。

+0

我目前有我的服务与https://github.com/dasMulli/dotnet-win32-service运行,但是当我可以尝试和捣鼓这个解决方案,因为它看起来像最好的未来打样,而且它看起来会是原生的做法。如果一切顺利,我会接受你的答案。 – DGaspar