Как поймать исключение и остановить службу Topshelf?
У меня есть служба windows topshelf, где я хочу выполнить некоторую проверку (т.е. если файл xml существует), и если проверка завершилась неудачно, мне нужно остановить службу Windows.
Поэтому я попытался выполнить проверку в методе Start(), а затем создать исключение:
public void Start()
{
if (!File.Exists(_xmlFile) throw new FileNotFoundException();
// Do some work here if xml file exists.
}
Тем не менее, служба Windows остается как процесс после исключения, который я должен убить вручную в диспетчере задач.
Есть ли способ не запускать службу, если выполняются определенные условия (т.е. файл не найден)?
Ответы
Ответ 1
Я "заимствовал" образец кода для функциональной настройки 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
});
Вам нужно будет поместить вашу проверку файловой системы ДО вышеприведенного кода. Подумайте об этом секунду. Суть службы заключается в том, чтобы убедиться, что она БЕСПЛАТНО и БЕСПЛАТНО. В первую очередь вы пытаетесь подорвать базовый принцип использования сервисных приложений. Вместо того, чтобы пытаться остановить службу из-за отсутствующего файла, определите способ оповещения вашего персонала службы поддержки и НЕ выполняйте все, что зависит от этого отсутствующего файла.
Ответ 2
Вы можете использовать объект 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);
}
}
}
Ответ 3
Каждый из методов WhenXxx может также принимать аргумент интерфейса HostControl, который может использоваться для запроса остановки службы, запроса дополнительного времени запуска/остановки и т.д.
В этом случае заменить подпись start() на bool start (HostControl hc). Сохраните ссылку на этот HostControl в службе следующим образом:
public bool Start(HostControl hc)
{
hostControl = hc;
Restart();
return true;
}
Теперь, когда вы хотите остановить службу, используйте следующий вызов:
hostControl.Stop();
Ответ 4
Я просто столкнулся с этой проблемой, и все вышеперечисленные ответы, похоже, усложняют ситуацию. Все, что вам нужно сделать, это использовать перегрузку WhenStarted
, которая принимает 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
}
}
Ответ 5
Мне было любопытно об этом с точки зрения лучшей практики или рекомендации в документации Topshelf, но ничего не удалось найти. Однако я нашел два отдельных комментария от phatboyg...
Лучший комментарий... как остановить службу по исключению, через этот вопрос (я вырезал некоторые детали):
Если ваш метод "Пуск" службы вызывает исключение, служба не запустится.
Как только служба будет запущена, если будет отменено необработанное исключение, служба остановится и сообщит об этом в качестве сбоя диспетчеру управления сервисом.
Если вам необходимо программно остановить службу, используйте метод HostControl Stop.
Поэтому я считаю, что самый простой ответ - это исключение.
Вы делали это, и вы упоминаете, что "служба Windows остается в виде процесса за исключением". Это похоже на несвязанную ошибку где-то в вашем коде, или, возможно, у вас как-то было многопользовательских экземпляров? Я тестировал эти сценарии сегодня утром и не видел, чтобы мой сервис работал после того, как выбрал исключение в методе start.
Также, относящийся к проверке перед HostFactory.Run, упомянутый в принятом ответе, через https://groups.google.com/forum/embed/#!topic/topshelf-discuss/nX97k3yOhJU:
"Ваше приложение должно ничего не делать, кроме как настроить NLog/Log4Net перед вызовом метода HostFactory.Run().
Ответ 6
Когда вы поймаете исключение, вы можете использовать метод ServiceBase.Stop()
, чтобы остановить службу самостоятельно.
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()