2011-02-01 6 views
46

Ive создал службу Windows под названием ProxyMonitor и im в настоящее время находится на этапе, когда служба устанавливает и удаляет способ, которым я хочу.Служба Windows для постоянного запуска

Так я исполняю приложение так:

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;

Что мне нужно сделать, чтобы служба постоянно активна, так как я должен был бы осуществлять мониторинг сети, мне нужно отслеживать изменения и т.д.


Update: 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"), который не срабатывает.

+0

'Thread = новая тема (ThreadWorker)' не будет работать –

+0

работает прекрасно, почему вы думаете, оно не будет? – RobertPitt

ответ

117

Обратный вызов 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); 
    } 
} 

Петля в то время как проверяет ManualResetEvent, чтобы увидеть, если он «установлен» или нет. Поскольку мы инициализировали объект с помощью false выше, эта проверка возвращает false. Внутри цикла мы спим в течение 1 секунды. Вы захотите заменить это на работу, которую вам нужно выполнить - контролировать настройки прокси-сервера и т. Д.

Наконец, в обратном вызове вашей службы Windows в OnStop() вы хотите, чтобы поток прекратил работать. Это легко использовать с помощью _shutdownEvent.

protected override void OnStop() 
{ 
    _shutdownEvent.Set(); 
    if (!_thread.Join(3000)) { // give the thread 3 seconds to stop 
     _thread.Abort(); 
    } 
} 

Надеюсь, это поможет.

+0

Спасибо за это, я все понял и теперь бежал, как ожидалось :) – RobertPitt

+4

Рад помочь. Для чего это стоит, у меня есть несколько подробных SO-руководств, которые показывают (1), как иметь свой собственный журнал в средстве просмотра событий (http://stackoverflow.com/questions/593454/easiest-language-for-creating -a-windows-service/593803 # 593803) и (2) как установить/удалить ваш сервис, не требуя InstallUtil.exe (http://stackoverflow.com/questions/1195478/how-to-make-a-net- окна-сервис запуск правых после самой установки/1195621 # 1195621). –

+0

Да, большое спасибо за вашу помощь, я раньше читал вашу первую статью в своем поиске победы, если вы хотите увидеть мой код, я разместил его здесь и оставил комментарий о том, на какой стадии im. http://pastebin.com/t8QQzXC9 – RobertPitt

0

Почему вы не создаете новый проект в своем решении типа Windows Service? Это устанавливает все структуры, которые необходимо реализовать, включая даже обработчики для событий запуска/остановки службы.

+1

Это частично учебный опыт, и я бы предпочел узнать, как это делается со дна. – RobertPitt

+0

Я бы сказал, что даже для обучения (особенно для обучения?) Вам лучше всего узнать, как VS создает строительные леса для службы Windows, а затем вы можете узнать, почему это работает и как это работает. Скорее, чем снизу вверх, что, как вы узнаете, гораздо более расстраивает. –

+0

Это правда, факт этот спор спорный, но здесь дело обстоит не так. Это приложение достигло 60%, и, возможно, в моем следующем приложении я начну с шаблона Windows Service. – RobertPitt

6

Вам необходимо выйти из обработчика OnStart, чтобы диспетчер службы понял, что ваша служба действительно началась. Чтобы заставить его работать так, как вы хотите, вы можете запустить таймер, который тикает с интервалом и обрабатывает, когда он тикает.

Edit:

Попробуйте положить System.Diagnostics.Debugger.Launch() в OnStart, чтобы увидеть, что происходит (и поставить точку останова в ThreadWorker). Я бы рекомендовал обернуть это в #if DEBUG, чтобы убедиться, что он не развернут.

я как раз и понял, что вы не даете ваш Thread имя:

Thread myThread = new Thread(ThreadWorker); 
myThread.Start(); 
+0

Должны ли быть какие-либо коды возврата, такие как 'return 0' или' return false', и нить будет нормально, так? – RobertPitt

+0

Нет; обработчик события OnStart возвращает void. Пока он выходит в разумные сроки (примерно через минуту, я думаю), диспетчер службы будет счастлив. –

+0

Плохо приготовьте. – RobertPitt

2

Конечно, не добавляя 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, вы можете получить скелет пример here.

1

Пример кода, продемонстрированный с помощью консольного приложения. надеюсь, что это поможет ..

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.. 
      } 

     } 
    } 
} 
Смежные вопросы