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



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



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




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


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



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



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

1193   13  

13 ответов:

  • создать консольное приложение, которое делает то, что вы ищете
  • использовать Windows "Запланированные Задачи" функциональность, чтобы это консольное приложение выполнялось в то время, когда вам это нужно для запуска

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

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

  • на Windows Forms приложение, вы можете нажать на Application.Idle событие и проверьте, достигли ли вы времени в день, чтобы вызвать свой метод. Этот метод вызывается только тогда, когда ваше приложение не занято другими вещами. Быстрая проверка, чтобы увидеть, было ли достигнуто ваше целевое время, не должна слишком сильно нагружать ваше приложение, я думаю...
  • в a 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();
    }
}

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

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

Как уже говорили другие, вы можете использовать консольное приложение для запуска по расписанию. То, что другие не сказали, что вы можете это приложение вызвать перекрестный процесс 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();
    }
}

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

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

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

Я создал простой планировщик, который прост в использовании и вам не нужно использовать внешние библиотеки. 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);
    }
}

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

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

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

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

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() в событии load формы. При запуске приложения он будет устанавливать значения для AppRestart Если current больше время перезапуска мы добавляем 1 день в AppRestart чтобы убедиться, что перезагрузка происходит вовремя и что мы не получаем исключение для ввода отрицательного значения в таймер. В tmrRestart_Elapsed событие выполнить любой код, который вам нужно запустить в это конкретное время. Если ваше приложение перезапускается самостоятельно, вам не обязательно останавливать таймер, но это тоже не больно, если приложение не перезапускается, просто вызовите RestartApp() метод снова и вы будете хорошо идти.

вот способ сделать это с помощью 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
}

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

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

30:00:00, 15:00:00, 07:30:00, 03:45:00, ... , 00:00:01, беги!

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

(преобразовано из 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 мс, это может быть увеличено, уменьшено или удалено в зависимости от accurcy вы требуете.

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

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

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

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

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

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

Comments

    Ничего не найдено.