Ich habe auf 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 (bestenfalls) im Code (keine externe Bibliothek erforderlich). Wie kann ich eine Methode täglich zu einer bestimmten Zeit 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 zum richtigen Zeitpunkt aufzurufen
Ich möchte einen effektiveren Weg, um 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 wissen, wie man eine E-Mail protokolliert / sendet. Deshalb muss ich eine Methode aufrufen und keinen Job planen.
Ich habe diese Lösung gefunden. Rufen Sie eine Methode zur festgelegten Zeit in Java in Java auf. Gibt es einen ähnlichen Weg in C #?
EDIT: Ich habe das getan. Ich habe einen Parameter in void Main () eingefügt und einen Bat (geplant von Windows Task Scheduler) erstellt, um das Programm mit diesem Parameter auszuführen. Das Programm wird ausgeführt, erledigt die Aufgabe und wird dann beendet. Wenn ein Auftrag fehlschlägt, kann er ein Protokoll schreiben und E-Mails senden. Dieser Ansatz passt gut zu meinen Anforderungen :)
quelle
Antworten:
Das ist wirklich alles was du brauchst!
Update: Wenn Sie dies in Ihrer App tun möchten, haben Sie mehrere Möglichkeiten:
Application.Idle
Ereignis tippen und prüfen, ob Sie die Tageszeit erreicht haben, um Ihre Methode aufzurufen. 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 stark belasten, denke ich ...Update Nr. 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 Event-Handler:
void checkForTime_Elapsed(object sender, ElapsedEventArgs e) { if (timeIsReady()) { SendEmail(); } }
quelle
timeIsReady()
Anruf?Ich habe einen einfachen Scheduler erstellt, der einfach zu verwenden ist und für den Sie keine externe Bibliothek benötigen. TaskScheduler ist ein Singleton, der Verweise auf die Timer speichert, damit Timer nicht durch Müll gesammelt werden. Er kann mehrere Aufgaben planen. Sie können den ersten Lauf (Stunde und Minute) einstellen, wenn zum Zeitpunkt der Planung diese Zeit abgelaufen ist. Beginnen Sie am nächsten Tag mit dieser Planung. Es ist jedoch einfach, den Code anzupassen.
Das Planen einer neuen Aufgabe ist so einfach. Beispiel: Um 11:52 Uhr ist die erste Aufgabe alle 15 Sekunden, das zweite Beispiel alle 5 Sekunden. Stellen Sie für die tägliche Ausführung 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 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); } }
quelle
Wenn ich Anwendungen erstelle, die solche Funktionen erfordern, verwende ich den Windows Task Scheduler immer über eine einfache .NET-Bibliothek , die ich gefunden habe.
In meiner Antwort auf eine ähnliche Frage finden Sie einen Beispielcode und weitere Erläuterungen.
quelle
Wie bereits erwähnt, können Sie eine Konsolen-App verwenden, um sie planmäßig auszuführen. Was andere nicht gesagt haben, ist, dass Sie mit dieser App ein prozessübergreifendes EventWaitHandle auslösen können, auf das Sie in Ihrer Hauptanwendung warten.
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(); } }
quelle
Die beste Methode, die ich kenne und wahrscheinlich die einfachste, besteht darin, den Windows Task Scheduler zu verwenden, um Ihren Code zu einer bestimmten Tageszeit auszuführen, oder Ihre Anwendung dauerhaft auszuführen und nach einer bestimmten Tageszeit zu suchen oder einen Windows-Dienst zu schreiben, der das ausführt gleich.
quelle
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 Tages-Timer. Wechseln Sie täglich zu stündlich oder wie auch immer die Periodizität sein soll.
quelle
Hier ist eine Möglichkeit, dies mit TPL zu tun. Keine Notwendigkeit, einen Timer zu erstellen / zu entsorgen usw.:
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 }
quelle
Dieses kleine Programm sollte die Lösung sein ;-)
Ich hoffe das hilft allen.
using System; using System.Threading; using System.Threading.Tasks; namespace DailyWorker { class Program { static void Main(string[] args) { var cancellationSource = new CancellationTokenSource(); var utils = new Utils(); var task = Task.Run( () => utils.DailyWorker(12, 30, 00, () => DoWork(cancellationSource.Token), cancellationSource.Token)); Console.WriteLine("Hit [return] to close!"); Console.ReadLine(); cancellationSource.Cancel(); task.Wait(); } private static void DoWork(CancellationToken token) { while (!token.IsCancellationRequested) { Console.Write(DateTime.Now.ToString("G")); Console.CursorLeft = 0; Task.Delay(1000).Wait(); } } } public class Utils { public void DailyWorker(int hour, int min, int sec, Action someWork, CancellationToken token) { while (!token.IsCancellationRequested) { var dateTimeNow = DateTime.Now; var scanDateTime = new DateTime( dateTimeNow.Year, dateTimeNow.Month, dateTimeNow.Day, hour, // <-- Hour when the method should be started. min, // <-- Minutes when the method should be started. sec); // <-- Seconds when the method should be started. TimeSpan ts; if (scanDateTime > dateTimeNow) { ts = scanDateTime - dateTimeNow; } else { scanDateTime = scanDateTime.AddDays(1); ts = scanDateTime - dateTimeNow; } try { Task.Delay(ts).Wait(token); } catch (OperationCanceledException) { break; } // Method to start someWork(); } } } }
quelle
Wenn eine ausführbare Datei ausgeführt werden soll, verwenden Sie Windows Scheduled Tasks. Ich gehe davon aus (vielleicht fälschlicherweise), dass Sie eine Methode in Ihrem aktuellen Programm ausführen möchten.
Warum nicht einfach einen Thread laufen lassen, der das letzte Datum, an dem die Methode aufgerufen wurde, kontinuierlich speichert?
Lassen Sie es beispielsweise jede Minute aufwachen. Wenn die aktuelle Zeit größer als die angegebene Zeit ist und das zuletzt gespeicherte Datum nicht das aktuelle Datum ist, rufen Sie die Methode auf und aktualisieren Sie das Datum.
quelle
Es mag nur ich sein, aber es schien, als wären die meisten dieser Antworten nicht vollständig oder würden nicht richtig funktionieren. Ich habe etwas sehr schnelles und schmutziges gemacht. Davon abgesehen bin ich mir nicht sicher, wie gut es ist, es so zu machen, 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); }
quelle
Ich habe kürzlich eine ac # App geschrieben, die täglich neu gestartet werden musste. Mir ist klar, dass diese Frage alt ist, aber ich glaube nicht, dass es weh tut, eine weitere mögliche Lösung hinzuzufügen. So habe ich tägliche Neustarts zu einem bestimmten Zeitpunkt durchgefü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 MethodeRestartApp()
in Ihr Formularladeereignis ein. Beim Start der Anwendung werden die Werte fürAppRestart
if festgelegt,current
die größer als die Neustartzeit sind, die wir um 1 Tag hinzufügen,AppRestart
um sicherzustellen, dass der Neustart pünktlich erfolgt und keine Ausnahme für das Einfügen eines negativen Werts in den Timer auftritt.tmrRestart_Elapsed
Führen Sie für den Fall den Code aus, den Sie zu diesem bestimmten Zeitpunkt benötigen. Wenn Ihre Anwendung von selbst neu gestartet wird, müssen Sie den Timer nicht unbedingt anhalten, aber es tut auch nicht weh. Wenn die Anwendung nicht neu gestartet wird, rufen Sie dieRestartApp()
Methode einfach erneut auf und Sie können loslegen.quelle
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(); } } }
quelle
Versuchen Sie, den Windows Task Scheduler zu verwenden. Erstellen Sie eine Exe, die keine Benutzereingaben auffordert.
https://docs.microsoft.com/en-us/windows/win32/taskschd/task-scheduler-start-page
quelle
Anstatt alle 60 Minuten eine Sekunde für die Ausführung festzulegen, können Sie die verbleibende Zeit berechnen und den Timer auf die Hälfte (oder einen anderen Bruchteil) davon einstellen. Auf diese Weise überprüfen Sie die Zeit nicht so genau, sondern behalten auch einen gewissen Grad an Genauigkeit bei, da sich das Zeitintervall verringert, je näher Sie Ihrer Zielzeit kommen.
Wenn Sie beispielsweise in 60 Minuten etwas tun möchten, sind die Timer-Intervalle ungefähr:
30:00:00, 15:00:00, 07:30:00, 03:45:00, ..., 00:00:01, RUN!
Ich verwende den folgenden Code, um einen Dienst einmal am Tag automatisch neu zu starten. Ich verwende einen Thread, weil ich festgestellt habe, dass Timer über lange Zeiträume unzuverlässig sind, während dies in diesem Beispiel teurer ist. Es ist der einzige, der für diesen Zweck erstellt wurde, sodass dies keine Rolle spielt.
(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 festgelegt. Dieses Intervall kann je nach der von Ihnen gewünschten Genauigkeit erhöht, verringert oder entfernt werden.
Denken Sie daran, Ihren Thread / Timer auch zu stoppen, wenn Ihre Anwendung geschlossen wird.
quelle
Ich habe einen einfachen Ansatz. Dies führt zu einer Verzögerung von 1 Minute, bevor die Aktion ausgeführt wird. Sie können auch Sekunden hinzufügen, um 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 } } }
quelle
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"; }
quelle
Lösung mit System.Threading.Timer:
private void nameOfMethod() { //do something } /// <summary> /// run method at 22:00 every day /// </summary> private void runMethodEveryDay() { var runAt = DateTime.Today + TimeSpan.FromHours(22); if(runAt.Hour>=22) runAt = runAt.AddDays(1.00d); //if aplication is started after 22:00 var dueTime = runAt - DateTime.Now; //time before first run ; long broj3 = (long)dueTime.TotalMilliseconds; TimeSpan ts2 = new TimeSpan(24, 0, 1);//period of repeating method long broj4 = (long)ts2.TotalMilliseconds; timer2 = new System.Threading.Timer(_ => nameOfMethod(), null, broj3, broj4); }
quelle