1

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 属性を追加する必要があるというエラー メッセージが表示されました (そして、呼び出してはならないメソッドが呼び出されたため、メソッドが失敗し、サービスがクラッシュしました)。そのため、Program.cs の Main() を "[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() の実行中に、前回の実行中に tick ハンドラーのブレークポイントに 3 回到達し、そのたびに設計どおりに戻りました。

4

1 に答える 1