web-dev-qa-db-fra.com

Comment puis-je déclencher un événement toutes les heures (ou un intervalle de temps spécifique chaque heure) dans .NET?

Je travaille sur un petit robot d'exploration Web qui s'exécutera dans la barre d'état système et explorera un site Web toutes les heures.

Quelle est la meilleure façon d'obtenir .NET pour déclencher un événement toutes les heures ou un autre intervalle pour effectuer une tâche. Par exemple, je veux exécuter un événement toutes les 20 minutes en fonction de l'heure. L'événement serait organisé à:

00:20
00:40
01:00
01:20
01:40

etc. La meilleure façon de penser à cela est de créer une boucle sur un thread, qui vérifie constamment si l'heure est divisible par un intervalle donné et déclenche un événement de rappel si l'heure est atteinte. J'ai l'impression qu'il doit y avoir une meilleure façon.

J'utiliserais un Timer mais je préférerais quelque chose qui suit un "programme" qui s'exécute à l'heure ou quelque chose dans ce sens.

Sans configurer mon application dans le planificateur de tâches Windows, est-ce possible?

MISE À JOUR:
J'ajoute mon algorithme pour calculer l'intervalle de temps d'une minuterie. Cette méthode prend un paramètre "minute", qui est l'heure à laquelle le temporisateur doit déclencher un tick. Par exemple, si le paramètre "minute" est égal à 20, la minuterie cochera aux intervalles du calendrier ci-dessus.

int CalculateTimerInterval(int minute)
{
    if (minute <= 0)
        minute = 60;
    DateTime now = DateTime.Now;

    DateTime future = now.AddMinutes((minute - (now.Minute % minute))).AddSeconds(now.Second * -1).AddMilliseconds(now.Millisecond * -1);

    TimeSpan interval = future - now;

    return (int)interval.TotalMilliseconds;
}

Ce code est utilisé comme suit:

static System.Windows.Forms.Timer t;
const int CHECK_INTERVAL = 20;


static void Main()
{
    t = new System.Windows.Forms.Timer();
    t.Interval = CalculateTimerInterval(CHECK_INTERVAL);
    t.Tick += new EventHandler(t_Tick);
    t.Start();
}

static void t_Tick(object sender, EventArgs e)
{
    t.Interval = CalculateTimerInterval(CHECK_INTERVAL);
}
30
Dan Herbert

System.Timers.Timer . Si vous souhaitez exécuter à des heures spécifiques de la journée, vous devrez déterminer combien de temps il faudra jusqu'à la prochaine fois et définir cela comme votre intervalle.

Ce n'est que l'idée de base. Selon la précision dont vous avez besoin, vous pouvez faire plus.

int minutes = DateTime.Now.Minute;
int adjust = 10 - (minutes % 10);
timer.Interval = adjust * 60 * 1000;  
31
tvanfosson

Vous pouvez trouver de l'aide sur Quartz.net http://quartznet.sourceforge.net/

11
suhair

Voici un exemple d'un système léger utilisant le timing des threads et un appel asynchrone.

Je sais qu'il y a des inconvénients, mais j'aime utiliser cela au lieu d'une minuterie lors du démarrage d'un long processus (comme les services backend programmés). Comme il s'exécute en ligne dans le thread de la minuterie, vous n'avez pas à vous soucier qu'il soit à nouveau lancé avant la fin de l'appel d'origine. Cela pourrait être étendu un peu pour lui faire utiliser un tableau d'heures comme heures de déclenchement ou lui ajouter des capacités supplémentaires. Je suis sûr que certains d'entre vous connaissent de meilleures façons.

    public Form1()
    {
        InitializeComponent();

        //some fake data, obviously you would have your own.
        DateTime someStart = DateTime.Now.AddMinutes(1);
        TimeSpan someInterval = TimeSpan.FromMinutes(2);

        //sample call
        StartTimer(someStart,someInterval,doSomething);
    }

    //just a fake function to call
    private bool doSomething()
    {
        DialogResult keepGoing = MessageBox.Show("Hey, I did something! Keep Going?","Something!",MessageBoxButtons.YesNo);
        return (keepGoing == DialogResult.Yes);
    }

    //The following is the actual guts.. and can be transplanted to an actual class.
    private delegate void voidFunc<P1,P2,P3>(P1 p1,P2 p2,P3 p3);
    public void StartTimer(DateTime startTime, TimeSpan interval, Func<bool> action)
    {
        voidFunc<DateTime,TimeSpan,Func<bool>> Timer = TimedThread;
        Timer.BeginInvoke(startTime,interval,action,null,null);
    }

    private void TimedThread(DateTime startTime, TimeSpan interval, Func<bool> action)
    {
        bool keepRunning = true;
        DateTime NextExecute = startTime;
        while(keepRunning)
        {
            if (DateTime.Now > NextExecute)
            {
                keepRunning = action.Invoke();
                NextExecute = NextExecute.Add(interval);
            }
            //could parameterize resolution.
            Thread.Sleep(1000);
        }            
    }
4
ExCodeCowboy

Une autre stratégie consiste à enregistrer le DERNIER TEMPS pendant lequel le processus a été exécuté et à déterminer si l'intervalle souhaité s'est écoulé depuis ce temps. Dans cette stratégie, vous coderiez votre événement pour qu'il se déclenche si le temps écoulé est égal à OR PLUS GRAND QUE l'intervalle souhaité. De cette façon, vous pouvez gérer les cas où de longs intervalles (une fois par jour, pour exemple) pourrait être manquée si l'ordinateur devait être arrêté pour une raison quelconque.

Ainsi, par exemple:

  • lastRunDateTime = 5/2/2009 à 20h
  • Je veux exécuter mon processus toutes les 24 heures
  • Lors d'un événement de minuterie, vérifiez si 24 heures OR PLUS se sont écoulées depuis la dernière exécution du processus.
  • Si oui, exécutez le processus, mettez à jour lastRunDateTime en y ajoutant l'intervalle souhaité (24 heures dans ce cas, mais ce dont vous avez besoin)

Évidemment, pour que cela se rétablisse après la panne du système, vous devrez stocker lastRunDateTime dans un fichier ou une base de données quelque part afin que le programme puisse reprendre là où il s'était arrêté lors de la récupération.

2
Casey Gay

System.Windows.Forms.Timer (ou System.Timers.Timer)

mais comme vous dites maintenant que vous ne voulez pas utiliser de minuteries, vous pouvez exécuter un processus d'attente léger sur un autre thread (vérifier l'heure, dormir quelques secondes, vérifier à nouveau ...) ou créer un composant qui déclenche un événement (en utilisant un processus d'attente léger) à certains moments ou intervalles planifiés

1
Steven A. Lowe