Подтвердить что ты не робот

Как вызвать метод ежедневно, в определенное время, на С#?

Я искал SO и нашел ответы о Quartz.net. Но это кажется слишком большим для моего проекта. Я хочу эквивалентное решение, но проще и (в лучшем случае) in-code (внешняя библиотека не требуется). Как я могу вызвать метод ежедневно, в определенное время?

Мне нужно добавить некоторую информацию об этом:

  • Самый простой (и уродливый) способ сделать это - проверить время каждую секунду/минуту и ​​вызвать метод в нужное время

Я хочу более эффективный способ сделать это, нет необходимости постоянно проверять время, и у меня есть контроль над тем, выполнено ли задание. Если метод выходит из строя (из-за каких-либо проблем), программа должна знать, чтобы писать для регистрации/отправки электронной почты. Вот почему мне нужно вызвать метод, а не планировать задание.

Я нашел это решение вызов метода в фиксированное время в Java на Java. Есть ли аналогичный способ в С#?

EDIT: Я сделал это. Я добавил параметр в void Main() и создал bat (запланированный планировщиком задач Windows) для запуска программы с этим параметром. Программа запускается, выполняет задание и затем выходит. Если сбой задания, он способен записывать журнал и отправлять электронную почту. Этот подход хорошо соответствует моим требованиям:)

4b9b3361

Ответ 1

Это действительно все, что вам нужно!

Обновление:, если вы хотите сделать это внутри своего приложения, у вас есть несколько вариантов:

  • в приложении Windows Forms, вы можете нажать на Application.Idle и проверить, хотите ли вы "Я достиг времени, чтобы вызвать ваш метод. Этот метод вызывается только тогда, когда ваше приложение не занято другими вещами. Быстрая проверка, чтобы узнать, достигнуто ли ваше целевое время, не стоит слишком сильно нажимать на ваше приложение, я думаю...
  • в веб-приложении ASP.NET существуют методы "имитировать" отправку запланированных событий - ознакомьтесь с этой статьей CodeProject
  • и, конечно же, вы можете просто просто "сворачивать свои собственные" в любом приложении .NET - посмотрите эту статью CodeProject для образца реализация

Обновить # 2: если вы хотите проверять каждые 60 минут, вы можете создать таймер, который просыпается каждые 60 минут, и если время наступает, он вызывает метод.

Что-то вроде этого:

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;

а затем в обработчике событий:

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

Ответ 2

Всякий раз, когда я создаю приложения, для которых требуются такие функции, я всегда использую планировщик задач Windows с помощью простой библиотеки .NET, которую я нашел.

Пожалуйста, см. мой ответ на аналогичный вопрос для примера кода и дополнительных пояснений.

Ответ 3

Как говорили другие, вы можете использовать консольное приложение для запуска по расписанию. То, что другие не сказали, - это то, что вы можете запустить это приложение через EventWaitHandle, который вы ожидаете в своем основном приложении.

Консольное приложение:

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

Главное приложение:

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();
    }
}

Ответ 4

Я создал простой планировщик, который прост в использовании, и вам не нужно использовать внешнюю библиотеку. TaskScheduler - это синглтон, который хранит ссылки на таймеры, поэтому таймеры не будут собирать мусор, он может планировать несколько задач. Вы можете установить первый запуск (час и минута), если на момент составления графика это время закончится, когда начнется планирование на следующий день в это время. Но легко настроить код.

Планирование новой задачи так просто. Пример: в 11:52 первая задача - на каждые 15 секунд, второй пример - на каждые 5 секунд. Для ежедневного выполнения установите 24 для параметра 3.

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
    });

Мое окно отладки:

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
...

Просто добавьте этот класс в свой проект:

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

Лучший способ, который я знаю и, пожалуй, самый простой, - использовать планировщик задач Windows для выполнения вашего кода в определенное время суток или запускать приложение постоянно и проверять определенное время суток или писать службу Windows что делает то же самое.

Ответ 6

Я знаю, что это устарело, но как насчет этого:

Создайте таймер для запуска при запуске, который вычисляет время до следующего времени выполнения. При первом вызове времени выполнения отмените первый таймер и запустите новый ежедневный таймер. ежедневно меняться каждый час или независимо от того, что вы хотите, чтобы периодичность была.

Ответ 7

Если вы хотите, чтобы исполняемый файл запускался, используйте запланированные задачи Windows. Я собираюсь предположить (возможно, ошибочно), что вы хотите, чтобы метод запускался в вашей текущей программе.

Почему бы просто не запустить поток, непрерывно сохраняющий последнюю дату, когда был вызван метод?

Просыпайтесь каждую минуту (например), и если текущее время больше указанного времени, а последняя дата сохранена не текущая дата, вызовите метод, а затем обновите дату.

Ответ 8

Недавно я написал приложение С#, которое пришлось перезапускать ежедневно. Я понимаю, что этот вопрос старый, но я не думаю, что больно добавлять еще одно возможное решение. Так я обрабатывал ежедневные перезагрузки в указанное время.

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();
}

Чтобы гарантировать, что ваш таймер хранится в области видимости, я рекомендую создать его вне метода, используя метод System.Timers.Timer tmrRestart = new System.Timers.Timer(). Поместите метод RestartApp() в событие загрузки формы. Когда приложение запустится, будут установлены значения для AppRestart, если current больше, чем время перезапуска, мы добавляем 1 день до AppRestart, чтобы гарантировать, что перезапуск произойдет вовремя и что мы не получаем исключения для отрицательное значение в таймер. В событии tmrRestart_Elapsed запускается любой код, который вам нужен, в указанное время. Если ваше приложение перезапустится самостоятельно, вам необязательно останавливать таймер, но это тоже не повредит. Если приложение не перезапускается, просто вызовите метод RestartApp() еще раз, и вам будет хорошо идти.

Ответ 9

Это может быть только я, но казалось, что большинство из этих ответов не были полными или не будут работать правильно. Я сделал что-то очень быстрое и грязное. Это, как говорится, не уверен, насколько хорошо идея заключается в том, чтобы делать это таким образом, но она отлично работает каждый раз.

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);
}

Ответ 10

Здесь можно сделать это с помощью TPL. Нет необходимости создавать/удалять таймер и т.д.:

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
}

Ответ 11

Вместо того, чтобы устанавливать время для запуска каждую секунду каждые 60 минут, вы можете рассчитать оставшееся время и установить таймер на половину (или какую-то другую долю) этого. Таким образом, вы не проверяете время так много, но также поддерживаете определенную степень точности, поскольку интервал таймера уменьшает время приближения к целевому времени.

Например, если вы хотите сделать что-то через 60 минут, таймеры будут aproximatly:

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

Я использую следующий код для автоматического перезапуска службы один раз в день. Я использую нить, потому что я нашел таймеры ненадежными в течение длительного времени, в то время как это более дорогостоящее в этом примере, это единственное, что создано для этой цели, поэтому это не имеет значения.

(преобразован из VB.NET)

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);
    }
}

Примечание. Я установил минимальный интервал в 1000 мс, это может быть не изучено, уменьшено или удалено в зависимости от требуемой точности.

Не забудьте также остановить поток/таймер при закрытии приложения.

Ответ 12

У меня есть простой подход к этому. Это создает задержку в 1 минуту до того, как произойдет действие. Вы также можете добавить секунды, чтобы сделать Thread.Sleep(); короче.

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
        }
    }
}

Ответ 13

24 часа

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";
    }

Ответ 14

Я нашел это очень полезным:

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();
        }
    }
}