À l'aide d'un timer dans un service Windows - s'est écoulé gestionnaire d'événement continue, même lorsque la minuterie est désactivée

J'ai lu beaucoup de messages liés à des services Windows et l'utilisation de minuteries, mais je n'ai trouvé aucune raison de mon gestionnaire d'événement est toujours déclenché. Quelqu'un pourrait-il me diriger dans la bonne direction? Je veux savoir pourquoi ce qui se passe si je comprends bien, comment éviter cela à l'avenir.

Edit: L'événement onError gestionnaire n'est jamais invoqué (ou je l'aurais vu l'événement dans le journal des événements).

Minuterie: Système.Les minuteries.Minuterie

ServiceBase: Système.ServiceProcess.ServiceBase


Ici est la classe abstraite:

public abstract class ABCService : ServiceBase
{
//Members
protected Timer             invocationTimer;
protected Timer             wellnessTimer;
protected FileSystemWatcher fsw;
//Constructors
protected ABCService()
{
invocationTimer = new Timer();
wellnessTimer   = new Timer();
fsw             = null;
invocationTimer.AutoReset = false;
invocationTimer.Interval  = 30000; //30 seconds
invocationTimer.Elapsed  += new ElapsedEventHandler(invocationTimer_Elapsed);
wellnessTimer.AutoReset   = false;
wellnessTimer.Elapsed    += new ElapsedEventHandler(wellnessTimer_Elapsed);
}
//Methods
protected void invocationTimer_Elapsed(object o, ElapsedEventArgs args)
{
try
{
//log to event log
invocationTimer.Stop();
if ((new FileInfo(fsw.Path + "\\" + fsw.Filter)).Exists)
{
onCreated(this, new FileSystemEventArgs(WatcherChangeTypes.Created, fsw.Path, fsw.Filter));
}
}
catch (Exception x)
{
onError(this, new ErrorEventArgs(x));
}
}
protected void wellnessTimer_Elapsed(object o, ElapsedEventArgs args)
{
try
{
//log to event log
wellnessTimer.Stop();
wellnessTimer.Interval = 60000; //ms
if (fsw != null)
{
fsw.Dispose();
}
fsw = new FileSystemWatcher(ConfigurationManager.AppSettings["pathKey"], ConfigurationManager.AppSettings["filterKey"]);
invocationTimer.Start();
}
catch (Exception x)
{
onError(this, new ErrorEventArgs(x));
}
}
protected abstract void onCreated(object o, FileSystemEventArgs args);
protected virtual void onError(object o, ErrorEventArgs args)
{
//log to event log
wellnessTimer.Start();
}
protected override void OnStart(string[] args)
{
//log to event log
wellnessTimer.Interval = 5000; //5 seconds
wellnessTimer.Start();
}
protected override void OnStop()
{
//log to event log
wellnessTimer.Stop();
}
}

Ici est une instance de la classe:

public partial class Service1 : ABCService
{
//Members
private static object locket = new object();
private static DateTime LAST_RUN_TIME = DateTime.Now.AddSeconds(-10);
//Constructors
public Service1()
{
InitializeComponent();
}
//Methods
protected override void onCreated(object o, FileSystemEventArgs args)
{
lock (locket)
{
//log to event log
if ((DateTime.Now - LAST_RUN_TIME).Seconds >= 10)
{
//do stuff
}
else
{
//log to event log
invocationTimer.Stop();
invocationTimer.Start();
}
}
}
}

Voici le code généré automatiquement pour la classe partielle:

partial class Service1
{
///<summary> 
///Required designer variable.
///</summary>
private System.ComponentModel.IContainer components = null;
///<summary>
///Clean up any resources being used.
///</summary>
///<param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
///<summary> 
///Required method for Designer support - do not modify 
///the contents of this method with the code editor.
///</summary>
private void InitializeComponent()
{
//
//Service1
//
this.ServiceName = "Service1";
}
#endregion
}

Donc ce qui se passe exactement? Je suis à la recherche de mon journal des événements et je vois qu'une fois chaque minute, la wellnessTimer gestionnaire d'événements est appelé.

Voici ce que j'ai pense qui se passe, mais je suis évidemment faux:

1. Service is started via MMC
2. OnStart() method is invoked
3. wellnessTimer interval is set to 5 seconds
4. wellnessTimer start method is invoked
5. wellnessTimer_Elapsed event handler is invoked
6. wellnessTimer stop method is invoked
7. wellnessTimer interval is set to 5 minutes
8. invocationTimer start method is invoked
9. 30 seconds later, the invocationTimer_Elapsed method is invoked
10. invocationTimer stop method is invoked

À ce stade, les deux minuteries existe encore pour cette instance, mais doit être désactivé. J'ai débogué via attacher au processus dans Visual Studio 2010 et a marqué un ID de l'objet (l'expéditeur) transmis dans les gestionnaires d'événements. C'est le même objet que l'instance. Aussi, les deux compteurs dans la fenêtre variables locales avaient leur propriété enabled à false.

Cela fait de moi chose que je suis en utilisant l'héritage de manière incorrecte, ou quelque chose qui se passe avec le filetage. Je ne suis pas le meilleur à une de ces choses, mais si c'est grâce à eux s'il vous plaît laissez-moi savoir si je peux apprendre.

Merci à tous à l'avance.


Edit #2: Ici est quelques données de trace...

"o" représente l'objet passé dans le gestionnaire d'événements

ABCService() method invoked <--
ABCService() method invoked -->
Service1() method invoked <--
Service1() method invoked -->
OnStart() method invoked <--
OnStart() method invoked -->
wellnessTimer_Elapsed() method invoked <--
((System.Timers.Timer) o).Enabled  = False
((System.Timers.Timer) o).Interval = 5000
this.wellnessTimer.Enabled  = False
this.wellnessTimer.Interval = 5000
wellnessTimer_Elapsed() method invoked -->
invocationTimer_Elapsed() method invoked <--
((System.Timers.Timer) o).Enabled  = False
((System.Timers.Timer) o).Interval = 30000
this.invocationTimer.Enabled  = False
this.invocationTimer.Interval = 30000
invocationTimer_Elapsed() method invoked -->
wellnessTimer_Elapsed() method invoked <--
((System.Timers.Timer) o).Enabled  = False
((System.Timers.Timer) o).Interval = 60000
this.wellnessTimer.Enabled  = False
this.wellnessTimer.Interval = 60000
wellnessTimer_Elapsed() method invoked -->
invocationTimer_Elapsed() method invoked <--
((System.Timers.Timer) o).Enabled  = False
((System.Timers.Timer) o).Interval = 30000
this.invocationTimer.Enabled  = False
this.invocationTimer.Interval = 30000
invocationTimer_Elapsed() method invoked -->
  • Essayez de commenter les wellnessTimer.Start() sur la onError méthode. Peut-être (peut-être) quelque chose va mal et l'erreur de l'événement est déclenché?
  • La bonne direction est ici.
  • Vous pouvez essayer d'appeler à rebours.Dispose()
  • Aye, j'ai lu que trop. Mais je vais être en désaccord avec vous. Cette application est conçue pour fonctionner en continu; les compteurs à zéro ne doit pas être de tir sur tous les intervalles prédéterminés.
  • J'ai mis à jour mon code afin de refléter la journalisation des événements. L'événement onError gestionnaire n'est jamais invoquée.
InformationsquelleAutor The Cog | 2012-07-24