Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.Net Core 2.0 Windows Service

I'm trying to build a Windows Service in .Net Core 2.0 but I've been banging my head on the wall for a full day and no progress at all. Everything seems to be using Core 1.0/1.1 even the Microsoft documentation:

Host an ASP.NET Core app in a Windows Service

TopShelf doesn't support 2.0 as well, for what I've seen.

I've seen some weird solutions that put all the code in a .Net Standard Class Library and then use a .Net Framework application to host the Windows Service, but this doesn't look elegant in my eyes and I'm trying to get rid of.Net Framework altogether.

Is what I want to do even possible at the moment? Am I missing something really basic?

like image 554
DGaspar Avatar asked Oct 04 '17 09:10

DGaspar


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.

What is Windows Service in .NET Core?

An ASP.NET Core app can be hosted on Windows as a Windows Service without using IIS. When hosted as a Windows Service, the app automatically starts after server reboots.

Is .NET 2.0 still supported?

NET Framework 2.0 has been around for a decade but will be completely unsupported by Microsoft; the announced end of the extended support period is April 12, 2016. In lock-step with the . NET Framework, the corresponding version of Microsoft's development tool, Visual Studio 2005, is also at its end-of-life.


1 Answers

It is now possible to write a Windows Service in .NET Core 2.0 without third-party libraries, thanks to the release of the Windows Compatibility Pack (at the time of writing, still in prerelease). As the page itself warns:

But before you start porting, you should understand what you want to accomplish with the migration. Just porting to .NET Core because it's a new .NET implementation isn't a good enough reason (unless you're a True Fan).

In particular, writing a Windows Service in .NET Core may now be possible, but you will not get cross-platform compatibility out of the box, because the assemblies for platforms other than Windows will just throw a PlatformNotSupportedException if you attempt to use service code. Working around this is possible (using RuntimeInformation.IsOSPlatform, for example), but that's another question altogether.

Also, third-party libraries may still offer a nicer interface with regards to installing the service: as of writing, the current version of the compatibility pack (2.0.0-preview1-26216-02) does not support the System.Configuration.Install namespace, so the default approach with a ServiceProcessInstaller class and installutil will not work. More on that later.

With all that said, let's suppose you have created a brand new Windows service (Service1) from the project template (not strictly required since it contains nothing interesting, other than a class inheriting from ServiceBase). All you need to do to make it build on .NET Core 2.0 is to edit and replace the .csproj with the new format:

<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> 

And then delete properties\AssemblyInfo.cs since it's no longer required and will conflict with version information in the project itself.

If you already have a service and it has dependencies, the conversion may be more complicated. See here.

Now you should be able to run dotnet publish and get an executable. As mentioned, you can't use the ServiceProcessInstaller class to install the service, so you'll have to manually

  • register the event source the service uses;
  • create the actual service.

This can be done with some PowerShell. From an elevated prompt in the location that contains your published executable:

$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) 

This is not ideal in several ways: this hard-codes the path of the message resource file (we should really be determining where it is from the executable and the runtime paths in the registry), and it hard-codes the service name and executable name. You may want to give your project its own installation capabilities by doing some command-line parsing in Program.cs, or use one of the libraries mentioned in Cocowalla's answer.

like image 101
Jeroen Mostert Avatar answered Sep 25 '22 12:09

Jeroen Mostert