Служба Windows для постоянной работы
Ive создал службу Windows под названием ProxyMonitor и im в настоящее время на этапе установки и удаления службы, как я ее хочу.
Итак, я выполняю приложение следующим образом:
C:\\Windows\\Vendor\\ProxyMonitor.exe /install
Довольно объяснительно, а затем я добрался до services.msc
и запустил службу, но когда я это сделаю, я получаю следующее сообщение:
Служба прокси-монитора на локальном компьютере началась, а затем остановлена. Некоторые службы автоматически останавливаются, если нет работы, например, "Журналы производительности и оповещения"
Мой код выглядит так:
public static Main(string[] Args)
{
if (System.Environment.UserInteractive)
{
/*
* Here I have my install logic
*/
}
else
{
ServiceBase.Run(new ProxyMonitor());
}
}
И затем в классе ProxyMonitor у меня есть:
public ProxyMonitor()
{
}
protected override void OnStart(string[] args)
{
base.OnStart(args);
ProxyEventLog.WriteEntry("ProxyMonitor Started");
running = true;
while (running)
{
//Execution Loop
}
}
и onStop()
Я просто изменяю переменную running
на false
;
Что мне нужно сделать, чтобы сделать службу постоянно активной, так как мне нужно будет контролировать сеть, в которой мне нужно отслеживать изменения и т.д.
Обновление: 1
protected override void OnStart(string[] args)
{
base.OnStart(args);
ProxyEventLog.WriteEntry("ProxyMonitor Started");
Thread = new Thread(ThreadWorker);
Thread.Start();
}
В ThreadWorker
у меня есть ProxyEventLogger.WriteEntry("Main thread entered")
, который не срабатывает.
Ответы
Ответ 1
Обратный вызов OnStart()
должен возвращаться своевременно, поэтому вы хотите начать поток, где будет выполняться вся ваша работа. Я бы рекомендовал добавить в класс следующие поля:
using System.Threading;
private ManualResetEvent _shutdownEvent = new ManualResetEvent(false);
private Thread _thread;
В поле _thread
будет содержаться ссылка на объект System.Threading.Thread
, который вы создаете в обратном вызове OnStart()
. Поле _shutdownEvent
содержит конструкцию события на системном уровне, которая будет использоваться для сигнализации о прекращении работы потока при завершении работы службы.
В обратном вызове OnStart()
создайте и запустите свой поток.
protected override void OnStart(string[] args)
{
_thread = new Thread(WorkerThreadFunc);
_thread.Name = "My Worker Thread";
_thread.IsBackground = true;
_thread.Start();
}
Для этого вам нужна функция с именем WorkerThreadFunc
. Он должен соответствовать подписке System.Threading.ThreadStart
.
private void WorkerThreadFunc()
{
}
Если вы не поместите ничего в эту функцию, поток запустится, а затем сразу же выключится, поэтому вам придется поместить туда некоторую логику, которая в основном сохраняет поток в то время, пока вы выполняете свою работу. Здесь _shutdownEvent
пригодится.
private void WorkerThreadFunc()
{
while (!_shutdownEvent.WaitOne(0)) {
// Replace the Sleep() call with the work you need to do
Thread.Sleep(1000);
}
}
Цикл while проверяет ManualResetEvent
, чтобы убедиться, что он установлен или нет. Поскольку мы инициализировали объект с помощью false
выше, эта проверка возвращает false. Внутри цикла мы спим в течение 1 секунды. Вы захотите заменить это на работу, которую вы должны выполнить - контролировать настройки прокси-сервера и т.д.
Наконец, в обратном вызове OnStop()
вашей Службы Windows вы хотите, чтобы поток прекратил работу. Это легко использовать с помощью _shutdownEvent
.
protected override void OnStop()
{
_shutdownEvent.Set();
if (!_thread.Join(3000)) { // give the thread 3 seconds to stop
_thread.Abort();
}
}
Надеюсь, что это поможет.
Ответ 2
Вам нужно выйти из обработчика OnStart
, чтобы диспетчер службы понял, что ваша служба действительно началась. Чтобы он работал так, как вы хотите, вы можете запустить таймер, который тикает с интервалом и обрабатывает, когда он тикает.
Edit:
Попробуйте ввести System.Diagnostics.Debugger.Launch() в свой OnStart
, чтобы увидеть, что происходит (и поместите точку останова в ThreadWorker
). Я бы рекомендовал обернуть это в #if DEBUG
, чтобы убедиться, что он не развертывается.
Я просто понял, что вы не дадите свое имя Thread
:
Thread myThread = new Thread(ThreadWorker);
myThread.Start();
Ответ 3
Конечно, не добавление цикла while
в метод OnStart
. Это скажет OS, что служба не запущена, потому что она не смогла безопасно выйти из метода OnStart
. Обычно я создаю Timer
, который включен в методе OnStart
. Затем в методе Ticks
я вызываю необходимый метод, чтобы заставить аппликацию работать.
В качестве альтернативы вы можете сделать следующее:
// The main entry point for the process
static void Main()
{
System.ServiceProcess.ServiceBase[] ServicesToRun;
ServicesToRun = new System.ServiceProcess.ServiceBase[] { new WinService1() };
System.ServiceProcess.ServiceBase.Run(ServicesToRun);
}
Для получения дополнительных сведений о службах Windows вы можете получить пример скелета здесь.
Ответ 4
Пример кода, продемонстрированного с помощью консольного приложения. надеюсь, это поможет..
class Program
{
private static CancellationTokenSource _cancellationTokenSource;
private static ManualResetEvent _shutdownEvent = new ManualResetEvent(false);
private static Thread _serviceStartThread;
private static Thread _serviceStopThread;
private static int workcounter = 0;
static void Main(string[] args)
{
_cancellationTokenSource = new CancellationTokenSource();
_serviceStartThread = new Thread(DoWork);
_serviceStopThread = new Thread(ScheduledStop);
StartService();
StopService();
}
private static void StartService()
{
_serviceStartThread.Start();
}
private static void StopService()
{
_serviceStopThread.Start();
}
/// <summary>
/// Triggers a cancellation event for stopping the service in a timely fashion.
/// </summary>
private static void ScheduledStop()
{
while (!_shutdownEvent.WaitOne(0))
{
if (workcounter == 10)
{
_cancellationTokenSource.Cancel();
}
}
}
/// <summary>
/// Represents a long running Task with cancellation option
/// </summary>
private static void DoWork()
{
while (!_shutdownEvent.WaitOne(0))
{
if(!_cancellationTokenSource.Token.IsCancellationRequested)
{
workcounter += 1;
Console.Write(Environment.NewLine);
Console.Write("Running...counter: " + workcounter.ToString());
Thread.Sleep(1000);//Not needed, just for demo..
}
else
{
Console.Write(Environment.NewLine);
Console.Write("Recieved cancellation token,shutting down in 5 seconds.. counter: " + workcounter.ToString());
_shutdownEvent.Set();
Thread.Sleep(5000);//Not needed, just for demo..
}
}
}
}
Ответ 5
Почему бы вам не создать новый проект в своем решении типа Windows Service? Это устанавливает все структуры, которые необходимо реализовать, включая даже обработчики для событий запуска/остановки службы.