Search code examples
topshelf

Topshelf Service - Determine Runtime Configuration From App.Config and InstanceName


I would like to create a windows service, using Topshelf, where the runtime configuration is driven by the App.config, and a command line argument.

Stated differently, I'd like the config file (App.config) to contain all the possible configurations, and then have the service select the configuration to use at runtime based on an argument - either "instance", or a custom argument.

What I've put together works when run as a console app, but doesn't work as a service. When run as a service, with...

serviceExe.exe intall -group:test

...the code below correctly sets things like displayName and description. What doesn't happen is configGroup being set to non-null when passed into the constructor during ConstructUsing:

private static int Main()
{
    var msghHdlrs = ConfigurationManager.GetSection("domainMessageHandlers") as DomainMessageHandlersSection;

    string serviceName = "BDService";
    DomainEventHandlerGroup configGroup = null;

    var exitCode = HostFactory.Run(host =>
    {
        host.AddCommandLineDefinition("group", g => {
           configGroup = msghHdlrs.Groups.OfType<DomainEventHandlerGroup>().Single(group => group.Name == g);
        });
        host.ApplyCommandLine();

        host.Service<DomainEventSubscriberServiceAdapterCollection>(svc =>
        {
            svc.ConstructUsing(() =>
            {
                return new DomainEventSubscriberServiceAdapterCollection(configGroup);
            });

            svc.WhenStarted(app =>
            {
                app.StartAll();
            }).BeforeStartingService(t => t.RequestAdditionalTime(TimeSpan.FromSeconds(10)));

            svc.WhenStopped(app =>
            {
                app.StopAll();
            });
        });

        host.SetServiceName(serviceName);
        host.SetInstanceName(configGroup.Name);
        host.SetDisplayName(configGroup.DisplayName);
        host.SetDescription(configGroup.Description);

        host.RunAsNetworkService();
    });

    return (int)exitCode;
}

Bottom-line, it seems configGroup gets set for the purposes of things outside of host.Service, but not within. Why is that?

More importantly, is what I'm trying to do possible? Have I missed something?

EDIT

It appears I have the same configuration as Single command line parameter to control Topshelf windows service

and yet it's not working for me...


Solution

  • More importantly, is what I'm trying to do possible?

    No, it's not possible. Command line arguments are not passed along to the service's start command. There's an ImagePath registry key that holds the command executed upon service start up. Command line arguments provided aren't included there.

    This is unlikely to be feature we will support with Topshelf because it's hard to reason about why an activity works or doesn't work. What happens if you run start with different arguments but they don't get passed along? If you come up with a proposal that doesn't end up confusing for end users, I'd be happy to consider implementing it though. At this point, doing all configuration from the app.config is the supported solution.