20

我有一个 topshelf windows 服务,我想在其中进行一些检查(即是否存在 xml 文件),如果检查失败,我需要停止 windows 服务。

所以我尝试在 Start() 方法中进行检查,然后引发异常:

public void Start()
{
    if (!File.Exists(_xmlFile) throw new FileNotFoundException();
    // Do some work here if xml file exists.
}

但是,Windows 服务在异常之后作为一个进程保留,然后我必须在任务管理器中手动终止。

如果某些条件(即找不到文件)成立,有没有办法不运行服务?

4

6 回答 6

34

您可以使用 HostControl 对象并像这样修改您的方法:

public bool Start(HostControl hostControl)
{
    if (!File.Exists(_xmlFile) 
    {
        hostControl.Stop();
        return true;
    }

    // Do some work here if xml file exists.
    ...
}

您需要将 HostControl 传递给 Start 方法,如下所示:

HostFactory.Run(conf =>
{
    conf.Service<YourService>(svcConf =>
    {
        svcConf.WhenStarted((service, hostControl) =>
        {
            return service.Start(hostControl);
        }
    }
}
于 2015-01-30T15:49:57.663 回答
8

每个WhenXxx方法还可以带一个HostControl接口的参数,可以用来请求停止服务,请求额外的启动/停止时间等。

在这种情况下,将 start() 的签名更改为 bool start(HostControl hc)。在服务中保留对此 HostControl 的引用,如下所示:

public bool Start(HostControl hc)
{
    hostControl = hc;
    Restart();
    return true;
}

现在,当您要停止服务时,请使用以下调用:

hostControl.Stop();
于 2015-04-13T15:44:54.343 回答
5

从 Topshelf 文档中的最佳实践或建议的角度来看,我对此感到好奇,但找不到任何东西。然而,我确实找到了来自 phatboyg 的两条单独的评论......

最佳评论...如何通过此问题停止异常服务(我删除了一些细节):

如果你的服务的 Start 方法抛出异常,服务将无法启动。

一旦服务运行,如果抛出未处理的异常,服务将停止,并将其作为崩溃报告给服务控制管理器。

如果您需要以编程方式停止服务,请使用 HostControl 方法停止。

所以我认为最简单的答案是抛出异常。

您正在这样做,并且您提到“Windows 服务在异常后作为一个进程保留”。这似乎是您代码中某个不相关的错误,或者您可能以某种方式运行了多个实例?今天早上我一直在测试这些场景,并且在 start 方法中抛出异常后没有看到我的服务运行。

此外,与通过https://groups.google.com/forum/embed/#!topic/topshelf-discuss/nX97k3yOhJU接受的答案中提到的 HostFactory.Run 之前的检查有关:

“在调用 HostFactory.Run() 方法之前,您的应用程序应该只配置 NLog/Log4Net。”

于 2015-10-16T13:49:55.750 回答
4

我刚刚遇到了这个问题,上面所有的答案似乎都过于复杂了。您需要做的就是使用WhenStarted接受 a 的重载,Func<T,HostControl,bool>如果您的内部服务引导失败则返回 false。我认为hostControl.Stop()不需要明确调用。

//Here is bit from inside the .Service<T>() call
s.WhenStarted((YourService svc, HostControl hc) => svc.Start());

//And the svc.Start method would look something like this:
class YourService
{
   public bool Start() {
     //return true if all is well
     //or false if you want service startup to be halted
   }
}
于 2016-01-18T09:45:31.710 回答
3

我已经“借用”了 topshelf 功能设置的示例代码来证明一个观点:

HostFactory.Run(x =>                                 //1
    {
        x.Service<TownCrier>(s =>                        //2
        {
           s.ConstructUsing(name=> new TownCrier());     //3
           s.WhenStarted(tc => tc.Start());              //4
           s.WhenStopped(tc => tc.Stop());               //5
        });
        x.RunAsLocalSystem();                            //6

        x.SetDescription("Sample Topshelf Host");        //7
        x.SetDisplayName("Stuff");                       //8
        x.SetServiceName("stuff");                       //9
    });    

在上述代码运行之前,您必须对文件系统进行检查。让我们考虑一下。拥有服务的目的是确保它运行并保持运行。您首先试图颠覆拥有服务应用程序的基本原则。不要因为丢失文件而试图停止服务,而是想办法提醒您的支持人员,而不是根据丢失的文件做任何事情。

于 2014-05-21T19:24:06.313 回答
-4

当您捕获异常时,您可以使用ServiceBase.Stop()Method 自行停止服务。

try
{
    // Your Code
}
catch (Exception ex)
{
    // The code for stopping service
}

在某些情况下,您还可以使用多个 catch 块:

try
{
    // Your Code
}
catch (IndexOutOfRengeException ex)
{
    // The code for stopping service
}
catch (FileNotFoundException exc)
{
    // The code for stopping service
}

阅读更多关于ServiceBase.Stop()

于 2014-05-21T19:08:20.590 回答