24

I want to pass some custom arguments to the console app when I install and start it as a Windows Service via TopShelf.

When I use:

MyService install start /fooBar: Test

Console application fails:

[Failure] Command Line An unknown command-line option was found: DEFINE: fooBar = Test

Question:

How can I make my arguments to be recognizable by TopShelf so that I can consume their values?

yallie
  • 2,200
  • 1
  • 28
  • 26
pencilCake
  • 51,323
  • 85
  • 226
  • 363

1 Answers1

39

EDIT: This only works when running the .exe, not when running as a service. As an alternative you could add the option as a configuration value and read it at start-up (which is probably better practice anyway):

using System.Configuration;

// snip

string foobar = null;

HostFactory.Run(configurator =>
{
    foobar = ConfigurationManager.AppSettings["foobar"];

    // do something with fooBar

    configurator.Service<ServiceClass>(settings =>
    {
        settings.ConstructUsing(s => GetInstance<ServiceClass>());
        settings.WhenStarted(s => s.Start());
        settings.WhenStopped(s => s.Stop());
    });

    configurator.RunAsLocalService();
    configurator.SetServiceName("ServiceName");
    configurator.SetDisplayName("DisplayName");
    configurator.SetDescription("Description");
    configurator.StartAutomatically();
});

According to the documentation you need to specify the commands in this pattern:

-foobar:Test

You also need to add the definition in your service configuration:

string fooBar = null;

HostFactory.Run(configurator =>
{
    configurator.AddCommandLineDefinition("fooBar", f=> { fooBar = f; });
    configurator.ApplyCommandLine();

    // do something with fooBar

    configurator.Service<ServiceClass>(settings =>
    {
        settings.ConstructUsing(s => GetInstance<ServiceClass>());
        settings.WhenStarted(s => s.Start());
        settings.WhenStopped(s => s.Stop());
    });

    configurator.RunAsLocalService();
    configurator.SetServiceName("ServiceName");
    configurator.SetDisplayName("DisplayName");
    configurator.SetDescription("Description");
    configurator.StartAutomatically();
});
Laurence
  • 1,673
  • 11
  • 16
  • 4
    After AddCommandLineDefinition() and before // do something you need to add the following line: configurator.ApplyCommandLine(); – Todd Feb 06 '14 at 02:46
  • 1
    Can you add a commandline argument to the ServiceClass? Im trying to do that, but it wont work when I start it as a service. – fuLLMetaLMan Nov 18 '14 at 14:02
  • Yes. This is not working when installing/starting it as service. foobar is empty. @fuLLMetaLMan : Did you find an answer? – char m Nov 21 '14 at 08:39
  • Okey, thanks. I just dropped the argument and worked around it. Thanks. – fuLLMetaLMan Nov 24 '14 at 15:03
  • Where did you find the documentation for `AddCommandLineDefinition()`? I don't see it [in the docs I found.](http://docs.topshelf-project.com/en/stable/index.html) – Nick Spreitzer Aug 20 '15 at 21:46
  • According to Topshelf's author, command-line arguments don't work when installed as a service. You can hack around it by modifying the registry yourself though: http://stackoverflow.com/questions/29837596/topshelf-starting-threads-based-on-custom-parameters#29841660 – mikebridge Dec 10 '15 at 18:20
  • @Nick, and yes, TopShelf documentation is very spotty. Since you often pass lambdas within lambdas within lambdas, it's difficult to figure out how to set something up properly. – mikebridge Dec 10 '15 at 18:26
  • ... speaking of spotty documentation, I'm guessing that you shouldn't call `ApplyCommandLine()` explicitly. I noticed it was being called twice, so it must get called somewhere during app startup. In the above code, `fooBar` will be available by the time that the lambda that is passed to `configurator.Service` is evaluated. – mikebridge Dec 10 '15 at 18:39
  • 2
    "*Since you often pass lambdas within lambdas within lambdas, it's difficult to figure out how to set something up properly*" - by that reasoning would could argue "Since you often pass parameters within methods calling other methods, it's difficult to figure out how to set something up properly". Nested lambdas are no more difficult to deal with than regular methods. My guess is you're just not *familiar* with them. That's not a complexity problem, it's an educational and familiarity problem. – AaronHS Feb 14 '16 at 22:57