I have a service with multiple instances with different parameters for each instance, at the moment I'm setting these parameters manually (in another code to be exact) to Image Path of the service in Registry (e.g. HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\MyService$i00
). so our service installation is done in two steps.
I'm really interested to merge these steps in Topshelf installation for example like
MyService.exe install -instance "i00" -config "C:\i00Config.json"
I tried AddCommandLineDefinition
from TopShelf but it seems it only works during installation and running through console not the service itself (will not add anything to service Image Path).
I tried to see if its possible to do this with AfterInstall
from Topshelf without any luck. here is a test code to see if it going to work or not (but unfortunately Topshelf overwrites the registry after AfterInstall
call).
HostFactory.Run(x =>
{
x.UseNLog();
x.Service<MyService>(sc =>
{
sc.ConstructUsing(hs => new MyService(hs));
sc.WhenStarted((s, h) => s.Start(h));
sc.WhenStopped((s, h) => s.Stop(h));
});
x.AfterInstall(s =>
{
using (var system = Registry.LocalMachine.OpenSubKey("SYSTEM"))
using (var controlSet = system.OpenSubKey("CurrentControlSet"))
using (var services = controlSet.OpenSubKey("services"))
using (var service = services.OpenSubKey(string.IsNullOrEmpty(s.InstanceName)
? s.ServiceName
: s.ServiceName + "$" + s.InstanceName, true))
{
if (service == null)
return;
var imagePath = service.GetValue("ImagePath") as string;
if (string.IsNullOrEmpty(imagePath))
return;
var appendix = string.Format(" -{0} \"{1}\"", "config", "C:\i00config.json"); //only a test to see if it is possible at all or not
imagePath = imagePath + appendix;
service.SetValue("ImagePath", imagePath);
}
});
x.SetServiceName("MyService");
x.SetDisplayName("My Service");
x.SetDescription("My Service Sample");
x.StartAutomatically();
x.RunAsLocalSystem();
x.EnableServiceRecovery(r =>
{
r.OnCrashOnly();
r.RestartService(1); //first
r.RestartService(1); //second
r.RestartService(1); //subsequents
r.SetResetPeriod(0);
});
});
I couldn't find any relevant information about how it can be done using TopShelf so the question is, is it possible to do this with TopShelf?
Ok, as Travis mentioned, It seems there is no built-in feature or simple workaround for this problem. so I wrote a little extension for Topshelf based on a Custom Environment Builder (most of the code is borrowed form Topshelf project itself).
I posted the code on Github, in case others may find it useful, here is the Topshelf.StartParameters extension.
based on the extension my code would be like:
HostFactory.Run(x =>
{
x.EnableStartParameters();
x.UseNLog();
x.Service<MyService>(sc =>
{
sc.ConstructUsing(hs => new MyService(hs));
sc.WhenStarted((s, h) => s.Start(h));
sc.WhenStopped((s, h) => s.Stop(h));
});
x.WithStartParameter("config",a =>{/*we can use parameter here*/});
x.SetServiceName("MyService");
x.SetDisplayName("My Service");
x.SetDescription("My Service Sample");
x.StartAutomatically();
x.RunAsLocalSystem();
x.EnableServiceRecovery(r =>
{
r.OnCrashOnly();
r.RestartService(1); //first
r.RestartService(1); //second
r.RestartService(1); //subsequents
r.SetResetPeriod(0);
});
});
and I can simply set it with:
MyService.exe install -instance "i00" -config "C:\i00Config.json"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With