Почему событие "Истекший таймер" никогда не запускается?

У меня есть этот код в службе Windows:

public void ConfigureService()
{
    //timer = new Timer { Interval = 600000 };
    timer = new Timer { Interval = 10000 };
    // 10 minutes; 1 second while testing
    timer.Elapsed += timer_Tick;
    timer.Enabled = true;
    RoboRprtrLib.WriteToLog("RoboRprtrService has started");
}

private void timer_Tick(object sender, ElapsedEventArgs eeargs)
{
    timer.Elapsed -= timer_Tick;
    try
    {
        RoboRprtrLib.WriteToLog("Timer has ticked");
        RoboRprtrLib.GenerateAndEmailDueReports();
    }
    finally
    {
        timer.Elapsed += timer_Tick;
    }
}

ConfigureService() вызывается из Program.cs:

static void Main()
{
    // got this idea ("How to Debug or Test your Windows Service Without Installing it...") from http://www.codeproject.com/Tips/261190/How-to-Debug-or-Test-your-Windows-Service-Without
    #if(!DEBUG)
    var ServicesToRun = new ServiceBase[] 
    { 
        new RoboRprtrService() 
    };
    ServiceBase.Run(ServicesToRun);
    #else
    var rrs = new RoboRprtrService();
    rrs.ConfigureService();
    #endif
}

У меня есть точка останова в ConfigureService() на этой строке:

timer = new Timer { Interval = 10000 };

Это достигается; Я могу пройти через весь метод ConfigureService().

У меня есть точка останова в событии Elapsed/Tick в первой строке:

timer.Elapsed -= timer_Tick;

... и это никогда не достигается.

Почему бы и нет? Не установлен ли таймер на отключение через 10 секунд, в какой момент должен вызываться обработчик события Tick?

ОБНОВИТЬ

Это полный код класса, производного от ServiceBase:

public partial class RoboRprtrService : ServiceBase
{
    private Timer timer;

    public RoboRprtrService()
    {
        InitializeComponent();
    }

    protected override void OnStart(string[] args)
    {
        ConfigureService();
    }

    public void ConfigureService()
    {
        //timer = new Timer { Interval = 600000 };
        timer = new Timer { Interval = 50000 };
        // 10 minutes; 50 seconds while testing
        timer.Elapsed += timer_Tick;
        timer.Enabled = true;
        RoboRprtrLib.WriteToLog("RoboRprtrService has started");
    }

    private void timer_Tick(object sender, ElapsedEventArgs eeargs)
    {
        timer.Elapsed -= timer_Tick;
        try
        {
            RoboRprtrLib.WriteToLog("Timer has ticked");
            RoboRprtrLib.GenerateAndEmailDueReports();
        }
        finally
        {
            timer.Elapsed += timer_Tick;
        }
    }

    protected override void OnStop()
    {
        timer.Enabled = false;
        RoboRprtrLib.WriteToLog("RoboRprtrService has stopped");
    }

}

ОБНОВЛЕНИЕ 2

Мне кажется странным, но если я добавлю эту строку:

RoboRprtrLib.GenerateAndEmailDueReports();

... до конца метода ConfigureService() таймер в конечном итоге отключается.

ОБНОВЛЕНИЕ 3

Больше странностей: я получал ошибочные сообщения о необходимости добавить атрибут STAThread (и вызывался метод, который не должен был быть, что приводило к его сбою и сбою службы). Поэтому я украсил Main() в Program.cs как "[STAThread]", и теперь он работает как надо.

Таймер сработал несколько раз во время операции, но у меня есть код для выхода, если происходит обработка. Когда вызванный метод завершился, IDE "вспыхнул", словно говоря: "Боже! Я ухожу отсюда!"

Итак, мой код Program.cs теперь:

[STAThread]
static void Main()
{
    #if(!DEBUG)
    var ServicesToRun = new ServiceBase[] 
    { 
        new RoboRprtrService() 
    };
    ServiceBase.Run(ServicesToRun);
    #else
    var rrs = new RoboRprtrService();
    rrs.ConfigureService();
    Console.ReadLine();
    #endif
}

... и самый подходящий код в классе, производный от ServiceBase:

public void ConfigureService()
{
    //timer = new Timer { Interval = 600000 };
    timer = new Timer { Interval = 50000 };
    // 10 minutes; 50 seconds while testing
    timer.Elapsed += timer_Tick;
    timer.Enabled = true;
    RoboRprtrLib.WriteToLog("RoboRprtrService has started");
    operationIsRunning = true;
    RoboRprtrLib.GenerateAndEmailDueReports();
    operationIsRunning = false;
}

private void timer_Tick(object sender, ElapsedEventArgs eeargs)
{
    if (operationIsRunning) return;
    operationIsRunning = true;
    . . .

"If (operationIsRunning) return;" точка останова в обработчике тиков была достигнута три раза во время моего последнего запуска во время выполнения GenerateAndEmailDueReports(), и каждый раз, когда она, как было задумано, возвращалась.

1 ответ

Решение

Как сказал Hans Passant в комментариях, в режиме отладки ваш код будет завершен сразу после вызова ConfigureServiceтак что нет времени на timer быть выполненным.

В режиме релиза ServiceBase.Run блокирует поток до тех пор, пока служба не завершит работу, но в отладочной версии этого не происходит.

РЕДАКТИРОВАТЬ:

На самом деле я пытался с Console.ReadLine() и не остановился, по-видимому, стандартный ввод перенаправлен, просто попробуйте сохранить процесс, с бесконечным циклом или что-то.

Как это:

static void Main()
{
    // got this idea ("How to Debug or Test your Windows Service Without Installing it...") from http://www.codeproject.com/Tips/261190/How-to-Debug-or-Test-your-Windows-Service-Without
    #if(!DEBUG)
    var ServicesToRun = new ServiceBase[] 
    { 
        new RoboRprtrService() 
    };
    ServiceBase.Run(ServicesToRun);
    #else
    var rrs = new RoboRprtrService();
    rrs.ConfigureService();

    while (true)
        Thread.Sleep(100);
    #endif
}
Другие вопросы по тегам