![]() |
VOOZH | about |
dotnet add package Plinth.WindowsService --version 1.8.1
NuGet\Install-Package Plinth.WindowsService -Version 1.8.1
<PackageReference Include="Plinth.WindowsService" Version="1.8.1" />
<PackageVersion Include="Plinth.WindowsService" Version="1.8.1" />Directory.Packages.props
<PackageReference Include="Plinth.WindowsService" />Project file
paket add Plinth.WindowsService --version 1.8.1
#r "nuget: Plinth.WindowsService, 1.8.1"
#:package Plinth.WindowsService@1.8.1
#addin nuget:?package=Plinth.WindowsService&version=1.8.1Install as a Cake Addin
#tool nuget:?package=Plinth.WindowsService&version=1.8.1Install as a Cake Tool
Makes creating a windows service easy
1. Install as service
<OutputType>Exe</OutputType>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
be sure to add the --urls {URLS} parameter to your binpath
--urls http://localhost:5050;https://something/SetContentRoot() when using your own IWebHost/IHostInstall
> sc create {ServiceName} displayName= "{DisplayName}" binpath= "D:\full\path\app.exe --urls http://localhost:9090" start= auto
> sc description {ServiceName} "Service for Plinth WebApp"
Change path or params after installing
> sc config {ServiceName} binPath= "{PathAndParams}"
Delete service
> sc delete {ServiceName}
Start/Stop
> net start {ServiceName}
> net stop {ServiceName}
2. Standard ASP.NET Core project using NLog
--urls http://localhost:5050 to your Debug settings as command line arguments
--urls http://localhost:5050;https://something/public class Program
{
public static void Main(string[] args)
{
var log = StaticLogManagerSetup.BasicNLogSetup();
log.Debug("startup!");
WindowsServiceRunner.RunWebHost(
BuildWebHost,
args,
callbacks: new Dictionary<ServiceState, Action>()
{
[ServiceState.Starting] = () => log.Debug("Starting..."),
[ServiceState.Started] = () => log.Debug("Started"),
[ServiceState.Stopping] = () => log.Debug("Stopping..."),
[ServiceState.Stopped] = () => log.Debug("Stopped"),
});
log.Debug("exit!");
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.UseContentRoot(WindowsServiceRunner.FindContentRoot()) // <==== REALLY IMPORTANT!
.ConfigureLogging(builder => builder.AddNLog())
.CaptureStartupErrors(false)
.Build();
}
3. Console project (no web interface), without NLog
--urls http://localhost:5050 to your Debug settings as command line arguments
--urls http://localhost:5050;https://something/ static void Main(string[] args)
{
var log = StaticLogManagerSetup.ConfigureForConsoleLogging();
log.Debug("startup!");
var mycallbacks = new Dictionary<ServiceState, Action>()
{
[ServiceState.Starting] = () => log.Debug("Main: Starting..."),
[ServiceState.Started] = () => log.Debug("Main: Started"),
[ServiceState.Stopping] = () => log.Debug("Main: Stopping..."),
[ServiceState.Stopped] = () => log.Debug("Main: Stopped"),
};
try
{
// option 1, make your own host and hosted service
// WindowsServiceRunner.RunHost(BuildHost, args, callbacks: mycallbacks);
// option 2, make your own hosted service
// WindowsServiceRunner.RunHostedService(new LoggerService(), args, callbacks: mycallbacks);
// option 3, a cancellable user action
// WindowsServiceRunner.RunAction(MyAction, args, callbacks: mycallbacks);
// option 4, a cancellable user action (async)
WindowsServiceRunner.RunAsyncAction(MyAsyncAction, args, callbacks: mycallbacks);
}
catch (Exception e)
{
log.Fatal("failed during startup", e);
throw;
}
}
// needed for option 1
public static IHost BuildHost(string[] args) =>
new HostBuilder()
.UseContentRoot(WindowsServiceRunner.FindContentRoot()) // <==== REALLY IMPORTANT!
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService<LoggerService>();
})
.Build();
// needed for option 1 and option 2
public class LoggerService : IHostedService, IDisposable
{
private static readonly ILogger log = StaticLogManager.GetLogger();
public Task StartAsync(CancellationToken cancellationToken)
{
log.Debug("service start()");
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
public void Dispose()
{
_timer?.Dispose();
}
}
// option 3
private static void MyAction(CancellationToken token)
{
while (!token.IsCancellationRequested)
{
log.Debug("timer");
Task.Delay(TimeSpan.FromSeconds(2), token).Wait(); // try not to block on non cancellable calls
}
}
// option 4
private static async Task MyAsyncAction(CancellationToken token)
{
while (!token.IsCancellationRequested)
{
log.Debug("timer");
await Task.Delay(TimeSpan.FromSeconds(2), token); // try not to block on non cancellable calls
}
}
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0-windows7.0 net8.0-windows7.0 is compatible. net9.0-windows net9.0-windows was computed. net9.0-windows7.0 net9.0-windows7.0 is compatible. net10.0-windows net10.0-windows was computed. net10.0-windows7.0 net10.0-windows7.0 is compatible. |
This package is not used by any NuGet packages.
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.8.1 | 217 | 12/11/2025 |
| 1.8.0 | 366 | 11/13/2025 |
| 1.8.0-b211.72089fd9 | 270 | 11/12/2025 |
| 1.7.4 | 353 | 8/6/2025 |
| 1.7.3 | 163 | 8/2/2025 |
| 1.7.2 | 311 | 3/16/2025 |
| 1.7.1 | 272 | 12/12/2024 |
| 1.7.0 | 241 | 11/12/2024 |
| 1.6.6 | 242 | 11/8/2024 |
| 1.6.5 | 269 | 8/31/2024 |
| 1.6.4 | 251 | 8/2/2024 |
| 1.6.3 | 294 | 5/15/2024 |
| 1.6.2 | 303 | 2/16/2024 |
| 1.6.1 | 336 | 1/5/2024 |
| 1.6.0 | 312 | 11/30/2023 |
| 1.5.10-b186.aca976b4 | 185 | 11/30/2023 |
| 1.5.9 | 226 | 11/29/2023 |
| 1.5.9-b174.64153841 | 173 | 11/23/2023 |
| 1.5.9-b172.dfc6e7bd | 149 | 11/17/2023 |
| 1.5.9-b171.4e2b92e2 | 188 | 11/4/2023 |
net10.0 support