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

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

Quel est le meilleur moyen d'obtenir que. NET déclenche un événement toutes les heures ou un autre intervalle pour effectuer une tâche. Par exemple je veux lancer un événement toutes les 20 minutes en fonction de l'heure. L'événement serait soulevé à:

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

Et ainsi de suite. La meilleure façon de le faire est de créer une boucle sur un thread, qui vérifie constamment si le temps est divisible par un intervalle donné et déclenche un événement de rappel si le temps est atteint. Je me sens comme il a obtenu d'être une meilleure façon.

J'utiliserais un Timer mais je préférerais quelque chose qui suit un "horaire" qui fonctionne à 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 pour une minuterie. Cette méthode prend un paramètre" minute", qui est à quelle heure la minuterie devrait déclencher une coche. Par exemple, si le paramètre "minute" est 20, alors la minuterie cochera aux intervalles dans l'horaire 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);
}
29
demandé sur Jon Seigel 2008-11-21 06:59:15

6 réponses

Système.Minuterie.Timer . Si vous voulez exécuter à des moments précis de la journée, vous devrez déterminer combien de temps il est jusqu'à la prochaine fois et définir que votre intervalle.

C'est juste l'idée de base. Selon la précision que vous devez être, vous pouvez faire plus.

int minutes = DateTime.Now.Minute;
int adjust = 10 - (minutes % 10);
timer.Interval = adjust * 60 * 1000;  
31
répondu tvanfosson 2012-05-25 18:01:47

Vous pouvez trouver de l'aide auprès de Quartz.net http://quartznet.sourceforge.net/

11
répondu suhair 2008-11-21 04:03:34

Voici un exemple de système léger utilisant la synchronisation des threads et un appel asynch.

Je sais qu'il y a quelques inconvénients, mais j'aime l'utiliser au lieu d'une minuterie lors du lancement d'un processus de longue durée (comme les services backend schedualed). Comme il s'exécute en ligne dans le thread de la minuterie, vous n'avez pas à vous soucier de le relancer avant la fin de l'appel d'origine. Cela pourrait être étendu un peu pour le faire utiliser un tableau de datetimes comme temps de déclenchement ou ajouter quelques 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
répondu ExCodeCowboy 2008-11-21 06:35:56

Système.Windows.Forme.Minuterie (ou système.Minuterie.Timer)

Mais puisque maintenant vous dites que vous ne voulez pas utiliser de minuteries, vous pouvez exécuter un processus d'attente léger sur un autre thread (Vérifiez l'heure, dormez quelques secondes, vérifiez à nouveau l'heure...) ou créer un composant qui déclenche un événement (en utilisant un processus d'attente léger) à certaines heures ou intervalles planifiés

1
répondu Steven A. Lowe 2008-11-21 04:11:06

Une autre stratégie consiste à enregistrer la dernière fois que le processus a été exécuté et à déterminer si l'intervalle souhaité s'est écoulé depuis. Dans cette stratégie, vous devez coder votre événement pour déclencher si le temps écoulé est égal ou supérieur à l'intervalle souhaité. De cette façon, vous pouvez gérer les cas où de longs intervalles (une fois par jour, par exemple) pourraient être manqué si l'ordinateur était en panne pour une raison quelconque.

Par exemple:

  • lastRunDateTime = 5/2/2009 à 8pm
  • je veux exécuter mon processus toutes les 24 heures
  • lors d'un événement de minuterie, vérifiez si 24 heures ou 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 tout ce dont vous avez besoin)

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

1
répondu Casey Gay 2009-05-03 23:26:34

Mon but est d'exécuter une importation vers 03h00 tous les soirs.

Voici mon approche, en utilisant le système.Minuterie.Minuterie:

private Timer _timer;
private Int32 _hours = 0;
private Int32 _runAt = 3;

protected override void OnStart(string[] args)
{
    _hours = (24 - (DateTime.Now.Hour + 1)) + _runAt;
    _timer = new Timer();
    _timer.Interval = _hours * 60 * 60 * 1000;
    _timer.Elapsed += new ElapsedEventHandler(Tick);
    _timer.Start();
}

void Tick(object sender, ElapsedEventArgs e)
{
    if (_hours != 24)
    {
        _hours = 24;
        _timer.Interval = _hours * 60 * 60 * 1000;
    }

    RunImport();
}
-1
répondu hey 2011-09-26 12:28:29