简体   繁体   中英

Why is my Timer's Elapsed event never being fired?

I've got this code in a Windows Service:

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() is called from 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
}

I have a breakpoint in ConfigureService() on this line:

timer = new Timer { Interval = 10000 };

It is reached; I can step through the entire ConfigureService() method.

I have a breakpoint in the Elapsed/Tick event on the first line:

timer.Elapsed -= timer_Tick;

...and it is never reached.

Why not? Isn't the timer set to trip after 10 seconds, at which point the Tick event handler should be called?

UPDATE

This is the entire code for the class deriving from 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");
    }

}

UPDATE 2

It seems odd to me, but if I add this line:

RoboRprtrLib.GenerateAndEmailDueReports();

...to the end of the ConfigureService() method, the timer is eventually tripped.

UPDATE 3

More oddities: I was getting err msgs about needing to add the STAThread attribute (and a method was being called that shouldn't have been, which caused it to fail and the service to crash). So I decorated Main() in Program.cs with "[STAThread]" and now it works as it should.

The timer tripped several times during the operation, but I have code to exit if processing is occurring. When the called method completed, the IDE "flashed" as if to say, "Poof! I'm outta here!"

So my Program.cs code is now:

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

...and the most pertinent code in the class that derives from ServiceBase is:

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

The "if (operationIsRunning) return;" breakpoint in the tick handler was reached three times during my last run while GenerateAndEmailDueReports() was executing, and each time it, as designed, returned.

As Hans Passant said in comments, in debug mode you code will terminate immediately after calling ConfigureService , so there is no time for the timer to be executed.

In release mode ServiceBase.Run blocks the thread until the service has finished, but this doesn't happen in debug version.

EDIT :

Actually I tried with Console.ReadLine() and did not stop, apparently standard input is redirected, just try to keep the process running, with an infinite loop or something.

Like this:

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
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM