使用Topshelf设置服务启动参数

时间:2015-10-01 16:45:59

标签: c# topshelf

我有一个服务,每个实例都有多个具有不同参数的实例,目前我手动设置这些参数(准确地说是另一个代码)到注册表中服务的Image Path(例如{{1 }})。所以我们的服务安装分两步完成。

我真的很想在Topshelf安装中合并这些步骤,比如

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\MyService$i00

首先尝试

我尝试了TopShelf中的MyService.exe install -instance "i00" -config "C:\i00Config.json" ,但它似乎只能在安装过​​程中运行,并且通过控制台而不是服务本身运行(不会向服务Image Path添加任何内容)。

第二次尝试

我试着看看它是否可以用Topshelf中的AddCommandLineDefinition做到这一点而没有任何运气。这是一个测试代码,看看它是否能够工作(但遗憾的是Topshelf在AfterInstall调用后覆盖了注册表。)

AfterInstall

我无法找到有关如何使用TopShelf完成任何相关信息,所以问题是,是否可以使用TopShelf执行此操作?

3 个答案:

答案 0 :(得分:3)

要回答你的问题,Topshelf不可能做到这一点。我很兴奋你想出了如何管理ImagePath。但这就是问题的症结所在,关于这个主题的邮件列表(https://groups.google.com/d/msg/topshelf-discuss/Xu4XR6wGWxw/8mAtyJFATq8J)已经有过一些讨论,并且过去就这个问题进行了讨论。

最大的问题是,在将自定义参数应用于ImagePath时管理行为期望将是不直观的。例如,当您使用自定义命令行参数调用start时会发生什么?如果我们得到的东西不会让我感到困惑,我会乐于实现这个或接受PR,更不用说尝试使用了。现在,我强烈建议您使用配置而不是命令行参数来管理它,即使它意味着复制磁盘上的代码。

答案 1 :(得分:3)

好的,正如Travis提到的那样,似乎没有针对此问题的内置功能或简单的解决方法。所以我基于自定义环境构建器为Topshelf编写了一个小扩展(大部分代码都是从Topshelf项目本身借用的)。

我在Github上发布了代码,以防其他人发现它有用,这里是Topshelf.StartParameters扩展名。

基于扩展我的代码就像:

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);
        });
    });

我可以简单地设置它:

MyService.exe install -instance "i00" -config "C:\i00Config.json"

答案 2 :(得分:0)

以下解决方法仅仅是注册表更新。更新操作需要安装程序为编写扩展参数而需要的权限。

基本上,我们正在回复AfterInstall()事件。从Topshelf v4.0.3开始,在事件中调用AppendImageArgs()解决方法将导致你的args在 TS args之前出现。如果延迟调用,则在 TS args之后将显示

解决方法

private static void AppendImageArgs(string serviceName, IEnumerable<Tuple<string, object>> args)
{
  try
  {
    using (var service = Registry.LocalMachine.OpenSubKey($@"System\CurrentControlSet\Services\{serviceName}", true))
    {
      const string imagePath = "ImagePath";
      var value = service?.GetValue(imagePath) as string;
      if (value == null)
        return;
      foreach (var arg in args)
        if (arg.Item2 == null)
          value += $" -{arg.Item1}";
        else
          value += $" -{arg.Item1} \"{arg.Item2}\"";
      service.SetValue(imagePath, value);
    }
  }
  catch (Exception e)
  {
    Log.Error(e);
  }
}

示例电话

private static void AppendImageArgs(string serviceName)
{
  var args = new[]
  {
    new Tuple<string, object>("param1", "Hello"),
    new Tuple<string, object>("param2", 1),
    new Tuple<string, object>("Color", ConsoleColor.Cyan),
  };
  AppendImageArgs(serviceName, args);
}

会出现在ImagePath中的结果:

 -displayname "MyService Display Name" -servicename "MyServiceName" -param1 "Hello" -param2 "1" -Color "Cyan"

注意args出现在TS args之后,-displayname&amp; -servicename。在此示例中,在TS完成其安装业务后调用AppendImageArgs()调用。

可以使用诸如AddCommandLineDefinition()之类的Topshelf方法正常指定命令行参数。要强制处理args,请调用ApplyCommandLine()