webentwicklung-frage-antwort-db.com.de

Wie rufe ich eine Methode täglich zu einer bestimmten Zeit in C # auf?

Ich habe nach SO gesucht und Antworten zu Quartz.net gefunden. Aber es scheint zu groß für mein Projekt zu sein. Ich möchte eine gleichwertige Lösung, aber einfacher und (im besten Fall) in Code (keine externe Bibliothek erforderlich). Wie kann ich täglich zu einer bestimmten Zeit eine Methode aufrufen? 

Ich muss einige Informationen dazu hinzufügen:

  • der einfachste (und hässlichste) Weg, dies zu tun, besteht darin, die Zeit jede Sekunde/Minute zu überprüfen und die Methode zur richtigen Zeit aufzurufen

Ich möchte einen effektiveren Weg, dies zu tun, ohne die Zeit ständig überprüfen zu müssen, und ich habe die Kontrolle darüber, ob die Arbeit erledigt ist oder nicht. Wenn die Methode fehlschlägt (aufgrund von Problemen), sollte das Programm schreiben, um eine E-Mail zu schreiben/zu schreiben. Deshalb muss ich eine Methode aufrufen, nicht einen Job einplanen.

Ich habe diese Lösung gefunden Eine Methode zu fester Zeit in Java aufrufen in Java. Gibt es einen ähnlichen Weg in C #?

EDIT: Ich habe das getan. Ich fügte void Main () einen Parameter hinzu und erstellte einen Bat (geplant von Windows Task Scheduler), um das Programm mit diesem Parameter auszuführen. Das Programm wird ausgeführt, erledigt den Job und wird dann beendet. Wenn ein Job fehlschlägt, kann er Protokolle schreiben und E-Mails senden. Dieser Ansatz passt gut zu meinen Anforderungen :)

67
Vimvq1987
  • Erstellen Sie eine Konsolenanwendung, die Ihren Wünschen entspricht
  • Verwenden Sie die Windows-Funktionalität " Scheduled Tasks ", um die Konsolenanwendung zu dem Zeitpunkt auszuführen, zu dem Sie sie benötigen

Das ist wirklich alles was du brauchst!

Update: Wenn Sie dies in Ihrer App tun möchten, haben Sie mehrere Möglichkeiten:

  • in einer Windows Forms - App können Sie auf das Ereignis Application.Idle tippen und prüfen, ob Sie die Uhrzeit am Tag für den Aufruf Ihrer Methode erreicht haben. Diese Methode wird nur aufgerufen, wenn Ihre App nicht mit anderen Dingen beschäftigt ist. Eine schnelle Überprüfung, ob Ihre Zielzeit erreicht wurde, sollte Ihre App nicht zu sehr belasten, denke ich.
  • in einer ASP.NET-Webanwendung gibt es Methoden, um das Senden geplanter Ereignisse zu "simulieren". Schauen Sie sich dieses CodeProject-Artikel an.
  • und natürlich können Sie in jeder .NET-App einfach nur "rollen". Sehen Sie sich CodeProject-Artikel für eine Beispielimplementierung an

Update # 2: Wenn Sie alle 60 Minuten überprüfen möchten, können Sie einen Timer erstellen, der alle 60 Minuten aktiviert wird. Wenn die Zeit abgelaufen ist, wird die Methode aufgerufen.

Etwas wie das:

using System.Timers;

const double interval60Minutes = 60 * 60 * 1000; // milliseconds to one hour

Timer checkForTime = new Timer(interval60Minutes);
checkForTime.Elapsed += new ElapsedEventHandler(checkForTime_Elapsed);
checkForTime.Enabled = true;

und dann in Ihrem Eventhandler:

void checkForTime_Elapsed(object sender, ElapsedEventArgs e)
{
    if (timeIsReady())
    {
       SendEmail();
    }
}
70
marc_s

Wenn ich Anwendungen baue, die eine solche Funktionalität erfordern, benutze ich benutze den Windows Task Scheduler immer über eine einfache .NET-Bibliothek, die ich gefunden habe.

Bitte siehe meine Antwort auf eine ähnliche Frage für Beispielcode und weitere Erläuterungen.

9
Maxim Zaslavsky

Wie bereits erwähnt, können Sie eine Konsole-App zur geplanten Ausführung verwenden. Was andere nicht gesagt haben, ist, dass Sie mit dieser App ein Cross Process EventWaitHandle auslösen können, das Sie in Ihrer Hauptanwendung erwarten.

Konsolen-App:

class Program
{
    static void Main(string[] args)
    {
        EventWaitHandle handle = 
            new EventWaitHandle(true, EventResetMode.ManualReset, "GoodMutexName");
        handle.Set();
    }
}

Haupt-App:

private void Form1_Load(object sender, EventArgs e)
{
    // Background thread, will die with application
    ThreadPool.QueueUserWorkItem((dumby) => EmailWait());
}

private void EmailWait()
{
    EventWaitHandle handle = 
        new EventWaitHandle(false, EventResetMode.ManualReset, "GoodMutexName");

    while (true)
    {
        handle.WaitOne();

        SendEmail();

        handle.Reset();
    }
}
8
Courtney D

Ich habe einen einfachen Scheduler erstellt, der einfach zu bedienen ist, und Sie müssen keine externe Bibliothek verwenden. TaskScheduler ist ein Singleton, der Verweise auf den Timern aufrechterhält, damit die Timer nicht als Müll gesammelt werden. Sie können den ersten Durchlauf (Stunde und Minute) einstellen, wenn zum Zeitpunkt der Planung dieser Zeitpunkt überläuft. Es ist jedoch einfach, den Code anzupassen.

Das Planen einer neuen Aufgabe ist so einfach. Beispiel: Um 11:52 ist die erste Aufgabe alle 15 Sekunden, das zweite Beispiel alle 5 Sekunden. Für die tägliche Ausführung stellen Sie 24 auf den Parameter 3 ein.

TaskScheduler.Instance.ScheduleTask(11, 52, 0.00417, 
    () => 
    {
        Debug.WriteLine("task1: " + DateTime.Now);
        //here write the code that you want to schedule
    });

TaskScheduler.Instance.ScheduleTask(11, 52, 0.00139,
    () =>
    {
        Debug.WriteLine("task2: " + DateTime.Now);
        //here write the code that you want to schedule
    });

Mein Debug-Fenster:

task2: 07.06.2017 11:52:00
task1: 07.06.2017 11:52:00
task2: 07.06.2017 11:52:05
task2: 07.06.2017 11:52:10
task1: 07.06.2017 11:52:15
task2: 07.06.2017 11:52:15
task2: 07.06.2017 11:52:20
task2: 07.06.2017 11:52:25
...

Fügen Sie diese Klasse einfach zu Ihrem Projekt hinzu:

public class TaskScheduler
{
    private static TaskScheduler _instance;
    private List<Timer> timers = new List<Timer>();

    private TaskScheduler() { }

    public static TaskScheduler Instance => _instance ?? (_instance = new TaskScheduler());

    public void ScheduleTask(int hour, int min, double intervalInHour, Action task)
    {
        DateTime now = DateTime.Now;
        DateTime firstRun = new DateTime(now.Year, now.Month, now.Day, hour, min, 0, 0);
        if (now > firstRun)
        {
            firstRun = firstRun.AddDays(1);
        }

        TimeSpan timeToGo = firstRun - now;
        if (timeToGo <= TimeSpan.Zero)
        {
            timeToGo = TimeSpan.Zero;
        }

        var timer = new Timer(x =>
        {
            task.Invoke();
        }, null, timeToGo, TimeSpan.FromHours(intervalInHour));

        timers.Add(timer);
    }
}
5
jannagy02

Ich weiß, das ist alt, aber wie wäre es damit:

Erstellen Sie einen Timer, der beim Start ausgelöst wird und die Zeit bis zur nächsten Laufzeit berechnet. Brechen Sie beim ersten Aufruf der Laufzeit den ersten Timer ab und starten Sie einen neuen Tagestimer. Ändern Sie täglich in stündlich oder wie auch immer Sie die Periodizität haben möchten.

4
mansoor

Die beste Methode, die ich kenne und wahrscheinlich die einfachste ist, besteht darin, den Windows Task Scheduler zu verwenden, um Ihren Code zu einer bestimmten Tageszeit auszuführen oder Ihre Anwendung permanent laufen zu lassen und eine bestimmte Tageszeit zu überprüfen oder einen Windows-Dienst zu schreiben, der das ausführt gleich. 

4

Hier ist eine Möglichkeit, dies mit TPL zu tun. Es ist nicht notwendig, einen Timer zu erstellen/zu entsorgen.

void ScheduleSomething()
{

    var runAt = DateTime.Today + TimeSpan.FromHours(16);

    if (runAt <= DateTime.Now)
    {
        DoSomething();
    }
    else
    {
        var delay = runAt - DateTime.Now;
        System.Threading.Tasks.Task.Delay(delay).ContinueWith(_ => DoSomething());
    }

}

void DoSomething()
{
    // do somethig
}
1
Gino

Wenn Sie eine ausführbare Datei ausführen möchten, verwenden Sie Windows Scheduled Tasks. Ich gehe davon aus (vielleicht irrtümlich), dass Sie möchten, dass eine Methode in Ihrem aktuellen Programm ausgeführt wird.

Warum sollte ein Thread nicht ständig fortlaufend das letzte Datum speichern, an dem die Methode aufgerufen wurde?

Lassen Sie es jede Minute aufwachen (zum Beispiel). Wenn die aktuelle Uhrzeit größer als die angegebene Zeit ist und das letzte Datum nicht das aktuelle Datum ist, rufen Sie die Methode auf und aktualisieren Sie das Datum.

1
paxdiablo

Ich habe vor kurzem eine C # App geschrieben, die täglich neu gestartet werden musste. Mir ist klar, dass diese Frage alt ist, aber ich denke nicht, dass es weh tut, eine andere mögliche Lösung hinzuzufügen. So habe ich tägliche Neustarts zu einer bestimmten Zeit ausgeführt.

public void RestartApp()
{
  AppRestart = AppRestart.AddHours(5);
  AppRestart = AppRestart.AddMinutes(30);
  DateTime current = DateTime.Now;
  if (current > AppRestart) { AppRestart = AppRestart.AddDays(1); }

  TimeSpan UntilRestart = AppRestart - current;
  int MSUntilRestart = Convert.ToInt32(UntilRestart.TotalMilliseconds);

  tmrRestart.Interval = MSUntilRestart;
  tmrRestart.Elapsed += tmrRestart_Elapsed;
  tmrRestart.Start();
}

Um sicherzustellen, dass Ihr Timer im Gültigkeitsbereich bleibt, empfehle ich, ihn außerhalb der Methode mithilfe der System.Timers.Timer tmrRestart = new System.Timers.Timer()-Methode zu erstellen. Fügen Sie die Methode RestartApp() in Ihr Formularladeereignis ein. Wenn die Anwendung gestartet wird, werden die Werte für AppRestart festgelegt, wenn current größer als die Neustartzeit ist, die um 1 Tag zu AppRestart hinzugefügt wird, um sicherzustellen, dass der Neustart rechtzeitig erfolgt und dass keine Ausnahme für das Einfügen eines negativen Werts in den Timer auftritt. Führen Sie im Ereignis tmrRestart_Elapsed den Code aus, den Sie zu diesem Zeitpunkt ausführen möchten. Wenn Ihre Anwendung von selbst neu startet, müssen Sie den Timer nicht unbedingt stoppen, aber es schadet auch nicht. Wenn die Anwendung nicht neu gestartet wird, rufen Sie einfach die RestartApp()-Methode auf, und Sie können loslegen.

1
Fancy_Mammoth

Es mag nur ich sein, aber es schien, als ob die meisten dieser Antworten nicht vollständig waren oder nicht richtig funktionieren würden. Ich habe etwas sehr schnell und schmutzig gemacht. Das heißt, nicht sicher, wie gut eine Idee ist, es so zu tun, aber es funktioniert jedes Mal perfekt.

while (true)
{
    if(DateTime.Now.ToString("HH:mm") == "22:00")
    {
        //do something here
        //ExecuteFunctionTask();
        //Make sure it doesn't execute twice by pausing 61 seconds. So that the time is past 2200 to 2201
        Thread.Sleep(61000);
    }

    Thread.Sleep(10000);
}
1
Deathstalker

24 Stunden mal

var DailyTime = "16:59:00";
            var timeParts = DailyTime.Split(new char[1] { ':' });

            var dateNow = DateTime.Now;
            var date = new DateTime(dateNow.Year, dateNow.Month, dateNow.Day,
                       int.Parse(timeParts[0]), int.Parse(timeParts[1]), int.Parse(timeParts[2]));
            TimeSpan ts;
            if (date > dateNow)
                ts = date - dateNow;
            else
            {
                date = date.AddDays(1);
                ts = date - dateNow;
            }

            //waits certan time and run the code
            Task.Delay(ts).ContinueWith((x) => OnTimer());

public void OnTimer()
    {
        ViewBag.ErrorMessage = "EROOROOROROOROR";
    }
0

Anstatt für jede 60 Minuten eine Zeit einzustellen, können Sie die verbleibende Zeit berechnen und den Timer auf die Hälfte (oder einen anderen Bruchteil) dieser Zeit einstellen. Auf diese Weise können Sie die Zeit nicht so sehr kontrollieren, sondern auch einen gewissen Grad an Genauigkeit einhalten, da sich das Zeitintervall verringert, je näher Sie an Ihre Zielzeit kommen.

Wenn Sie beispielsweise in 60 Minuten etwas tun wollten, wären die Zeitintervalle ungefähr: 

30:00:00, 15:00:00, 07:30:00, 03:45:00, ..., 00:00:01, LAUFEN!

Ich verwende den folgenden Code, um einen Dienst einmal täglich automatisch neu zu starten. Ich verwende einen Thread, weil ich festgestellt habe, dass Zeitgeber über lange Zeiträume unzuverlässig sind. Dies ist jedoch in diesem Beispiel teurer, da es der einzige ist, der für diesen Zweck erstellt wurde. 

(Von VB.NET konvertiert)

autoRestartThread = new System.Threading.Thread(autoRestartThreadRun);
autoRestartThread.Start();

...

private void autoRestartThreadRun()
{
    try {
        DateTime nextRestart = DateAndTime.Today.Add(CurrentSettings.AutoRestartTime);
        if (nextRestart < DateAndTime.Now) {
            nextRestart = nextRestart.AddDays(1);
        }

        while (true) {
            if (nextRestart < DateAndTime.Now) {
                LogInfo("Auto Restarting Service");
                Process p = new Process();
                p.StartInfo.FileName = "cmd.exe";
                p.StartInfo.Arguments = string.Format("/C net stop {0} && net start {0}", "\"My Service Name\"");
                p.StartInfo.LoadUserProfile = false;
                p.StartInfo.UseShellExecute = false;
                p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
                p.StartInfo.CreateNoWindow = true;
                p.Start();
            } else {
                dynamic sleepMs = Convert.ToInt32(Math.Max(1000, nextRestart.Subtract(DateAndTime.Now).TotalMilliseconds / 2));
                System.Threading.Thread.Sleep(sleepMs);
            }
        }
    } catch (ThreadAbortException taex) {
    } catch (Exception ex) {
        LogError(ex);
    }
}

Hinweis Ich habe ein Mindestintervall von 1000 ms eingestellt. Je nach gewünschter Genauigkeit kann dies erhöht, verringert oder entfernt werden.

Denken Sie daran, auch Ihren Thread/Timer zu stoppen, wenn Ihre Anwendung geschlossen wird.

0
apc

Ich habe einen einfachen Ansatz dafür. Dies führt zu einer Verzögerung von 1 Minute, bevor die Aktion ausgeführt wird. Sie können auch Sekunden hinzufügen, um den Thread.Sleep () zu erstellen. kürzer.

private void DoSomething(int aHour, int aMinute)
{
    bool running = true;
    while (running)
    {
        Thread.Sleep(1);
        if (DateTime.Now.Hour == aHour && DateTime.Now.Minute == aMinute)
        {
            Thread.Sleep(60 * 1000); //Wait a minute to make the if-statement false
            //Do Stuff
        }
    }
}
0
Gustav Bok

Ich fand das sehr nützlich:

using System;
using System.Timers;

namespace ScheduleTimer
{
    class Program
    {
        static Timer timer;

        static void Main(string[] args)
        {
            schedule_Timer();
            Console.ReadLine();
        }

        static void schedule_Timer()
        {
            Console.WriteLine("### Timer Started ###");

            DateTime nowTime = DateTime.Now;
            DateTime scheduledTime = new DateTime(nowTime.Year, nowTime.Month, nowTime.Day, 8, 42, 0, 0); //Specify your scheduled time HH,MM,SS [8am and 42 minutes]
            if (nowTime > scheduledTime)
            {
                scheduledTime = scheduledTime.AddDays(1);
            }

            double tickTime = (double)(scheduledTime - DateTime.Now).TotalMilliseconds;
            timer = new Timer(tickTime);
            timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
            timer.Start();
        }

        static void timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            Console.WriteLine("### Timer Stopped ### \n");
            timer.Stop();
            Console.WriteLine("### Scheduled Task Started ### \n\n");
            Console.WriteLine("Hello World!!! - Performing scheduled task\n");
            Console.WriteLine("### Task Finished ### \n\n");
            schedule_Timer();
        }
    }
}
0
JoKeRxbLaCk