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
We just need System.ServiceProcess.ServiceController NuGet package to run a .NET Core application as Windows Service.
Following is the .csproj file,
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
<RuntimeIdentifier>win7-x64</RuntimeIdentifier>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.ServiceProcess.ServiceController"
Version="4.5.0" />
</ItemGroup>
</Project>
Program.cs file,
using System.ServiceProcess;
namespace WindowsService101
{
class Program
{
static void Main(string[] args)
{
using (var service = new HelloWorldService())
{
ServiceBase.Run(service);
}
}
}
}
public class HelloWorldService : ServiceBase
{
protected override void OnStart(string[] args)
{
// Code Here
}
protected override void OnStop()
{
// Code Here
}
}
Build and Publish the solution.
Open Cmd Prompt in Admin mode from the .exe folder Sample: \WindowsService101\bin\Debug\netcoreapp2.1\publish
sc create binPath=""
sc start
ASP.NET Core in a Windows Service for .NET Core 2.2
. Make the following changes to an existing ASP.NET Core project to run the app as a service:
Requires: PowerShell 6.2 or later
Framework-dependent Deployment (FDD):
Framework-dependent deployment (FDD) relies on the presence of a shared system-wide version of .NET Core on the target system. When the FDD scenario is used with an ASP.NET Core Windows Service app, the SDK produces an executable (*.exe), called a framework-dependent executable.
Add a Windows Runtime Identifier (RID) to the <PropertyGroup>
that contains the target framework. In the following example, the RID is set to win7-x64
. Add the <SelfContained>
property set to false
. These properties instruct the SDK to generate an executable (.exe) file for Windows.
A web.config file, which is normally produced when publishing an ASP.NET Core app, is unnecessary for a Windows Services app. To disable the creation of the web.config file, add the <IsTransformWebConfigDisabled>
property set to true
.
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
<RuntimeIdentifier>win7-x64</RuntimeIdentifier>
<SelfContained>false</SelfContained>
<IsTransformWebConfigDisabled>true</IsTransformWebConfigDisabled>
</PropertyGroup>
Self-contained Deployment (SCD):
Self-contained deployment (SCD) doesn't rely on the presence of shared components on the target system. The runtime and the app's dependencies are deployed with the app to the hosting system.
Confirm the presence of a Windows Runtime Identifier (RID) or add a RID to the <PropertyGroup>
that contains the target framework. Disable the creation of a web.config file by adding the <IsTransformWebConfigDisabled>
property set to true
.
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
<RuntimeIdentifier>win7-x64</RuntimeIdentifier>
<IsTransformWebConfigDisabled>true</IsTransformWebConfigDisabled>
</PropertyGroup>
Program.Main
public class Program
{
public static void Main(string[] args)
{
var isService = !(Debugger.IsAttached || args.Contains("--console"));
if (isService)
{
var pathToExe = Process.GetCurrentProcess().MainModule.FileName;
var pathToContentRoot = Path.GetDirectoryName(pathToExe);
Directory.SetCurrentDirectory(pathToContentRoot);
}
var builder = CreateWebHostBuilder(
args.Where(arg => arg != "--console").ToArray());
var host = builder.Build();
if (isService)
{
// To run the app without the CustomWebHostService change the
// next line to host.RunAsService();
host.RunAsCustomService();
}
else
{
host.Run();
}
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureLogging((hostingContext, logging) =>
{
logging.AddEventLog();
})
.ConfigureAppConfiguration((context, config) =>
{
// Configure the app here.
})
.UseStartup<Startup>();
}
Publish a Framework-dependent Deployment (FDD):
dotnet publish --configuration Release --output c:\svc
Publish a Self-contained Deployment (SCD)
The RID must be specified in the <RuntimeIdenfifier>
(or <RuntimeIdentifiers>
) property of the project file. Supply the runtime to the -r|--runtime option of the dotnet publish
command.
dotnet publish --configuration Release --runtime win7-x64 --output c:\svc
Grant write/read/execute access to the app's folder using the icacls command via an administrative PowerShell 6 command shell.
icacls "{PATH}" /grant "{USER ACCOUNT}:(OI)(CI){PERMISSION FLAGS}" /t
Command:
icacls "c:\svc" /grant "ServiceUser:(OI)(CI)WRX" /t
Use the RegisterService.ps1 PowerShell script to register the service. From an administrative PowerShell 6 command shell, execute the script with the following command:
.\RegisterService.ps1
-Name MyService
-DisplayName "My Cool Service"
-Description "This is the Sample App service."
-Exe "c:\svc\SampleApp.exe"
-User Desktop-PC\ServiceUser
Start the service with the Start-Service -Name {NAME}
PowerShell 6 command.
Start-Service -Name MyService
Handle starting and stopping events
internal class CustomWebHostService : WebHostService
{
private ILogger _logger;
public CustomWebHostService(IWebHost host) : base(host)
{
_logger = host.Services
.GetRequiredService<ILogger<CustomWebHostService>>();
}
protected override void OnStarting(string[] args)
{
_logger.LogInformation("OnStarting method called.");
base.OnStarting(args);
}
protected override void OnStarted()
{
_logger.LogInformation("OnStarted method called.");
base.OnStarted();
}
protected override void OnStopping()
{
_logger.LogInformation("OnStopping method called.");
base.OnStopping();
}
}
Extension method:
public static class WebHostServiceExtensions
{
public static void RunAsCustomService(this IWebHost host)
{
var webHostService = new CustomWebHostService(host);
ServiceBase.Run(webHostService);
}
}
Program.Main:
host.RunAsCustomService();
Set the content root path to the app's folder:
Program.Main:
var pathToExe = Process.GetCurrentProcess().MainModule.FileName;
var pathToContentRoot = Path.GetDirectoryName(pathToExe);
Directory.SetCurrentDirectory(pathToContentRoot);
CreateWebHostBuilder(args)
.Build()
.RunAsService();
Source:
https://github.com/aspnet/AspNetCore.Docs/tree/master/aspnetcore/host-and-deploy/windows-service/
https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/windows-service?view=aspnetcore-2.2
Maybe this is a complete cop-out, but remember that with greater docker support, you may be able to build out a service that runs within a container. At that point, it would still be .net core (2.0) but running on your windows box. What's more, you could deploy just about anywhere in the future.
As dotnet core matures, I this is a better and better solution, assuming your service doesn't require resources local to the host.
For those finding this question but want to implement a windows service with .NET Core 3.x
https://csharp.christiannagel.com/2019/10/15/windowsservice/
A combination of the generic host plus the background service plus the commandline tool sc and you have a windows service.