How do I run two parts of code at the same time - c#

I have a problem where I have some values that needs to be updated every 5 sec. But in between I have to update my newsfeed too.
How do I run my newsfeed?:
My newsfeed will be run while in a loop, moving the text left.
Problem:
I will need somehow to run all my other code at the same time as the newsfeed is also running. But I can't figure out a way to do this. I can't place my newsfeed updater inside my main loop, because then it update with the rest too, resulting in the newsfeed bugging.
Code:
public partial class Form1 : Form
{
ServiceReference1.monitorSoapClient ds = new ServiceReference1.monitorSoapClient();
public Form1()
{
InitializeComponent();
}
private void lblTempOut_Click(object sender, EventArgs e)
{
}
private async void btnUpdate_Click(object sender, EventArgs e)
{
int i = 0;
do
{
lblTempOut.Text = ds.OutdoorTemp().ToString("N2") + " °C";
lblInsideTemp.Text = ds.StockTemp().ToString("N2") + " °C";
lblHumitidyOutside.Text = ds.OutdoorHumidity().ToString("N2") + " %";
lblStockHumitidy.Text = ds.StockHumidity().ToString("N2") + " %";
{
listBoxMinItem.Items.Clear();
ds.StockItemsUnderMin().ForEach(item =>
{
listBoxMinItem.Items.Add(item);
});
}
{
listBoxMostSold.Items.Clear();
ds.StockItemsMostSold().ForEach(item =>
{
listBoxMostSold.Items.Add(item);
});
}
{
ListBoxOverMax.Items.Clear();
ds.StockItemsUnderMin().ForEach(item =>
{
ListBoxOverMax.Items.Add(item);
});
}
TimeZoneInfo timeZoneCopenhagen = TimeZoneInfo.FindSystemTimeZoneById("Central European Standard Time");
DateTime CEST = DateTime.UtcNow;
DateTime ConvertedTimeCEST = TimeZoneInfo.ConvertTimeFromUtc(CEST, timeZoneCopenhagen);
lblTimeCopenhagen.Text = ConvertedTimeCEST.ToString();
TimeZoneInfo timeZoneLondon = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
DateTime GMT = DateTime.UtcNow;
DateTime ConvertedTimeGMT = TimeZoneInfo.ConvertTimeFromUtc(GMT, timeZoneLondon);
lblTimeLondon.Text = ConvertedTimeGMT.ToString();
TimeZoneInfo timeZoneSST = TimeZoneInfo.FindSystemTimeZoneById("Singapore Standard Time");
DateTime SST = DateTime.UtcNow;
DateTime ConvertedTimeSST = TimeZoneInfo.ConvertTimeFromUtc(SST, timeZoneSST);
lblTimeSingapore.Text = ConvertedTimeSST.ToString();
string newsFeedUrl = #"https://nordjyske.dk/rss/nyheder";
XmlReader reader = XmlReader.Create(newsFeedUrl);
SyndicationFeed syndFeed = SyndicationFeed.Load(reader);
reader.Close();
foreach (SyndicationItem item in syndFeed.Items)
{
newsFeed.Text += item.Title.Text + " ";
}
await Task.Delay(5000);
} while (i == 0);
Move();
}
private void ResetNewsPosition()
{
newsFeed.Left = newsContainer.Width;
}
private async void Move()
{
while (true)
{
ResetNewsPosition();
while (newsFeed.Location.X + newsFeed.Width >= 0)
{
newsFeed.Left -= 1;
await Task.Delay(10);
}
}
}
If anyone have any suggestions, please do let me know :)

You do this by using Timers. When writing UI code you should not write loops that take longer than a few hundred ms to complete. And if your loop contains a Task.Delay or a Thread.Sleep it is a strong indicator that you should use a timer instead. Task.Delay will internally use a timer, and in some cases it can be convenient to use if you want a single short delay, but whenever you make statements like "I want to run X ever Y seconds" it will probably be better to use a timer directly.
This lets you interleave different functions, i.e. you run each function after each other on a single thread, possibly with different frequencies. For example, rewrite your move function to
private void MoveNewsPos(){
newsFeed.Left -= 1;
if(newsFeed.Location.X + newsFeed.Width < 0)
ResetNewsPosition();
}
and call this from a timer with a 10ms interval.
The other option is to use multi threading. But this is mostly useful when you are doing things that are computationally expensive. It is not useful at all when most of the task consists of updating the UI.
For completeness there is also asynchronous operations that are mostly useful when doing IO work, to allow the UI thread to do other things while waiting from results from the disk or network.
see also why are there 5 timer classes for different types of timers.

To start a task about every 5 seconds, my advice would be to use class System.Timers.Timer. It is a Component, so it must be disposed when your form is disposed. Best way to do this is to add it to your form's property components.
private Timer CreateUpdateTimer()
{
TimeSpan timerTime = TimeSpan.FromSeconds(5);
Timer timer = new Timer(timerTime.TotalMilliSeconds);
// Hook up the Elapsed event for the timer.
timer.Elapsed += OnTimedEvent;
timer.AutoReset = true;
timer.Enabled = true;
return timer;
}
Consider to create a procedure with the TimeoutTime as TimeSpan parameter
// will be called every 5 seconds:
private static void OnTimedEvent(Object source, ElapsedEventArgs e)
{
this.UpdateValues(); // the procedure that updates your values
}
In your constructor:
public Form1()
{
InitializeComponent();
this.components.Add(this.CreateUpdateTimer());
}

Related

backgroundworker starts more than once

I have a issue that I really dont know why it occurs at all. I wpf c# application that use a timer to start a backgroundworker, sometimes the backgroundworker start the task twice, and I don't know why. The code I use is this....
private void startScheduledTask()
{
// Timer settings and start
dpTimer.Interval = TimeSpan.FromMilliseconds(CalculateTimerInterval(CHECK_INTERVAL));
dpTimer.Tick += new EventHandler(StartScheduledActivity);
dpTimer.Start();
}
private void StartScheduledActivity(Object sender, EventArgs args)
{
// Timer tick has occured, start scheduled work
StartScheduledWork();
dpTimer.Interval = TimeSpan.FromMilliseconds(CalculateTimerInterval(CHECK_INTERVAL));
}
private void StartScheduledWork()
{
MyHeavyWorker = new System.ComponentModel.BackgroundWorker();
if ((!MyHeavyWorker.IsBusy) && (MyHeavyWorker != null))
{
MyHeavyWorker.WorkerReportsProgress = true;
MyHeavyWorker.WorkerSupportsCancellation = true;
MyHeavyWorker.ProgressChanged += MyHeavyWorker_ProgressChanged;
MyHeavyWorker.DoWork += MyHeavyWorker_DoWork;
MyHeavyWorker.RunWorkerCompleted += MyHeavyWorker_RunWorkerCompleted;
MyHeavyWorker.RunWorkerAsync();
}
}
private void MyHeavyWorker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
// This method sometime run twice at a time
FetchSomeFiles();
}
public int CalculateTimerInterval(int minute)
{
if (minute <= 0)
{
minute = 60;
}
DateTime CurrTime = DateTime.Now;
DateTime now = DateTime.Now;
DateTime future = now.AddMinutes((minute - (now.Minute % minute))).AddSeconds(now.Second * -1).AddMilliseconds(now.Millisecond * -1);
TimeSpan interval = future - now;
NextExecutionTime = future.ToShortTimeString();
NextExecutionDateTime = NextExecutionTime.ToString();
return Convert.ToInt32(interval.TotalMilliseconds);
}
Can anyone see why the method FetchSomeFiles sometimes runs twice at the same time?
It's quite simply because you are each time initializing a new instance of your backgroundworker - so if your timer event occurs before the previous backgroundworker is done it will start a second time with another bg Worker instance. Keep your Backgroundworker reference on class level and initialize it only once.
Do the same thing with the eventhandlers you are adding - move them to the class constructor or to a method called once when your object is instanciated.
//Put this line on class level and only initialize it once.
MyHeavyWorker = new System.ComponentModel.BackgroundWorker();
//Call this once to initialize your Backgroundworker
public void InitializeBackgroundWorker()
{
MyHeavyWorker.WorkerReportsProgress = true;
MyHeavyWorker.WorkerSupportsCancellation = true;
MyHeavyWorker.ProgressChanged += MyHeavyWorker_ProgressChanged;
MyHeavyWorker.DoWork += MyHeavyWorker_DoWork;
MyHeavyWorker.RunWorkerCompleted += MyHeavyWorker_RunWorkerCompleted;
}
Then check for the MyHeavyWorker.IsBusy of your one and only instance to check if it is currently doing some work before deciding to call RunWorkerAsync().
Another method would also be to just stop your timer with dpTimer.Stop() in StartScheduledActivity before you launch your BackgroundWorker and call dpTimer.Start() again in MyHeavyWorker_RunWorkerCompleted. Of course you will have to reconsider how you would like to calculate your next interval since with this solution the countdown does start after your backgroundworker is done - which could be considerably later than the point of the start.
Check
if MyHeavyWorker.IsBusy
before starting the task inside the DoWork() Method. This method will check if DoWork() is still running and will not start another call of this method until it is finished

If the time is 1:00am Run the function in C#?

Is there a way in C# where if the time in PC or system says 1:00AM the function will run. I know this can be achieved using timer, but how can I do it? The code I am tinkering right now is this:
var t = new Timer { Enabled = true, Interval = 1 * 1000 };
t.Tick += delegate { mem_details(); };
But this code runs the function every 1 seconds, Do I need to compute 1:00AM to Seconds so I can do it using this code?
Please have a look to Quartz scheduler, I suppose it will help
http://quartz-scheduler.org/
Here is an example of how to configure Quartz for different time using cron strings:http://quartz-scheduler.org/documentation/quartz-2.2.x/examples/Example3.
You can use the online cron generator to select time you need.
You could always go with Microsoft's Reactive Framework to do this. The schedulers in there are incredibly robust.
You could write this code:
var start = DateTimeOffset.Now;
start = start.Date.AddHours(start.Hour == 0 ? 1.0 : 25.0);
/* start is now set for the next 1AM */
/* So schedule it */
Scheduler.Default.Schedule(start, reschedule =>
{
/* Do you thing as it's now 1AM */
/* And now reschedule to run tomorrow at 1AM */
reschedule(DateTimeOffset.Now.Date.AddHours(25.0));
});
Since you're using a 1 second timer why not check the time every tick?
EDIT:
Ok I changed my code a bit. It's still a 1 second timer (1000 milliseconds) but now when the timer tick event triggers, it only looks at the current hour and minute. Thus if your program is running a bit slow it will still run your process at 1 AM.
The global variable "lastRunDate" stores the date of when the last process run. This needs to be updated before your process runs just in case your process takes longer than a second to complete.
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
private String lastRunDate = "";
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
timer1.Interval = 1000;
timer1.Enabled = true;
}
private void timer1_Tick(object sender, EventArgs e)
{
if (lastRunDate != System.DateTime.Now.ToString("yyyy-MM-dd"))
{
String str = System.DateTime.Now.ToString("h:mm tt");
if (str.Equals("1:00 AM"))
{
lastRunDate = System.DateTime.Now.ToString("yyyy-MM-dd");
MessageBox.Show(str);
}
}
}
}
}
You can use timer and check time in it. For example
var t = new Timer { Enabled = true, Interval = 1 * 1000 };
t.Tick += delegate (object sender, EventArgs e)
{
if (DateTime.Now.TimeOfDay.TotalHours > 1 && DateTime.Now.TimeOfDay.TotalHours < 2)
{
mem_details();
(sender as Timer).Enabled=false;
}
};

Background Worker Check For When It's Midnight?

I want to create a background worker for a WinForm that triggers code whenever midnight rolls by.
I have an idea of how to do it, but I'm pretty sure it's not the best way to do it.
while(1==1)
{
//if Datetime.Now == midnight, execute code
//sleep(1second)
}
Use a System.Timers.Timer and at application start up just calculate the difference between DateTime.Now and DateTime.Today.AddDays(0). Then set the interval for that amount.
I actually did something just like this recently:
public static class DayChangedNotifier
{
private static Timer timer;
static DayChangedNotifier()
{
timer = new Timer(GetSleepTime());
timer.Elapsed += (o, e) =>
{
OnDayChanged(DateTime.Now.DayOfWeek);
timer.Interval = this.GetSleepTime();
};
timer.Start();
SystemEvents.TimeChanged += new EventHandler(SystemEvents_TimeChanged);
}
private static void SystemEvents_TimeChanged(object sender, EventArgs e)
{
timer.Interval = GetSleepTime();
}
private static double GetSleepTime()
{
var midnightTonight = DateTime.Today.AddDays(1);
var differenceInMilliseconds = (midnightTonight - DateTime.Now).TotalMilliseconds;
return differenceInMilliseconds;
}
private static void OnDayChanged(DayOfWeek day)
{
var handler = DayChanged;
if (handler != null)
{
handler(null, new DayChangedEventArgs(day));
}
}
public static event EventHandler<DayChangedEventArgs> DayChanged;
}
AND:
public class DayChangedEventArgs : EventArgs
{
public DayChangedEventArgs(DayOfWeek day)
{
this.DayOfWeek = day;
}
public DayOfWeek DayOfWeek { get; private set; }
}
Useage: DayChangedNotified.DayChanged += ....
Instead you could user a Timer and set the timer tick interval to be the time between Now() and midnight.
I have no idea why polling solutions were voted up when Microsoft solved this type of problem years ago by adding a windows service to handle timing. Just create a scheduled task to run the exe. No extra overhead.
you can use Quartz to schedule that. Maybe is like a cannon to kill a mosquito in this scenario, but that's is the only scheduling job framework i know and works excellent.
Don't use polling. Instead, set up a timer task, set it to fire at midnight, and add an event to process.
TimeSpan timeBetween = DateTime.Today.AddDays(1) - DateTime.Now;
System.Timers.Timer t = new System.Timers.Timer();
t.Elapsed += new System.Timers.ElapsedEventHandler(t_Elapsed);
t.Interval = 1000 * timeBetween.Seconds;
t.Start();
I'm a little confuse about why you need a WinForm, will it be running at midnight? If all you need is some sort process to run, use the windows scheduler to run it at midnight. (On XP, but I believe Win server should be similar)Control Panel -> Scheduled Tasks -> Add Scheduled Task -> Fill out the wizard. Save you a lot of coding.

.NET, event every minute (on the minute). Is a timer the best option?

I want to do stuff every minute on the minute (by the clock) in a windows forms app using c#. I'm just wondering whats the best way to go about it ?
I could use a timer and set its interval to 60000, but to get it to run on the minute, I would have to enable it on the minute precisely, not really viable.
I could use a timer and set its interval to 1000. Then within its tick event, I could check the clocks current minute against a variable that I set, if the minute has changed then run my code. This worries me because I am making my computer do a check every 1 second in order to carry out work every 1 minutes. Surely this is ugly ?
I'm using windows forms and .Net 2.0 so do not want to use the DispatchTimer that comes with .Net 3.5
This must be a fairly common problem. Have any of you a better way to do this?
Building on the answer from aquinas which can drift and which doesn't tick exactly on the minute just within one second of the minute:
static System.Timers.Timer t;
static void Main(string[] args)
{
t = new System.Timers.Timer();
t.AutoReset = false;
t.Elapsed += new System.Timers.ElapsedEventHandler(t_Elapsed);
t.Interval = GetInterval();
t.Start();
Console.ReadLine();
}
static double GetInterval()
{
DateTime now = DateTime.Now;
return ((60 - now.Second) * 1000 - now.Millisecond);
}
static void t_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
Console.WriteLine(DateTime.Now.ToString("o"));
t.Interval = GetInterval();
t.Start();
}
On my box this code ticks consistently within .02s of each minute:
2010-01-15T16:42:00.0040001-05:00
2010-01-15T16:43:00.0014318-05:00
2010-01-15T16:44:00.0128643-05:00
2010-01-15T16:45:00.0132961-05:00
How about:
int startin = 60 - DateTime.Now.Second;
var t = new System.Threading.Timer(o => Console.WriteLine("Hello"),
null, startin * 1000, 60000);
Creating a Timer control that fires every 1 second (and usually does nothing but a simple check) will add negligible overhead to your application.
Simply compare the value of Environment.TickCount or DateTime.Now to the last stored time (the previous 'minute tick'), and you should have a reasonably precise solution. The resolution of these two time values is about 15ms, which should be sufficient for your purposes.
Do note however that the interval of the Timer control is not guaranteed to be that precise or even anywhere now, since it runs on the Windows message loop, which is tied in with the responsiveness of the UI. Never rely on it for even moderately precise timing - though it is good enough for firing repeating events where you can check the time using a more sensitive method such as one of the two given above.
You can nail this with reactive extensions which will take care of lots of timer related problems for you (clock changes, app hibernation etc). Use Nuget package Rx-Main and code like this:
Action work = () => Console.WriteLine(DateTime.Now.ToLongTimeString());
Scheduler.Default.Schedule(
// start in so many seconds
TimeSpan.FromSeconds(60 - DateTime.Now.Second),
// then run every minute
() => Scheduler.Default.SchedulePeriodic(TimeSpan.FromMinutes(1), work));
Console.WriteLine("Press return.");
Console.ReadLine();
Read here (search for "Introducing ISchedulerPeriodic") to see all the issues this is taking care of: http://blogs.msdn.com/b/rxteam/archive/2012/06/20/reactive-extensions-v2-0-release-candidate-available-now.aspx
I jsut wrote this class using the WPF DispatcherTimer but you can swap the dispatcher for any timer that supports changing when it's woken from sleep state.
The class is constructed with a fixed time step and supprts Start/Stop/Reset, Start/Stop/Start works like a resume operation. The timer is like a stopwatch in that regard.
A clock implementation would simply create the class with a interval of 1 second and listen to the event. Be wary though that this is a real-time clock, if the tick event takes longer than the interval to finish you'll notice that the clock will try and catch up to real-time this will cause a burst of tick events being raised.
public class FixedStepDispatcherTimer
{
/// <summary>
/// Occurs when the timer interval has elapsed.
/// </summary>
public event EventHandler Tick;
DispatcherTimer timer;
public bool IsRunning { get { return timer.IsEnabled; } }
long step, nextTick, n;
public TimeSpan Elapsed { get { return new TimeSpan(n * step); } }
public FixedStepDispatcherTimer(TimeSpan interval)
{
if (interval < TimeSpan.Zero)
{
throw new ArgumentOutOfRangeException("interval");
}
this.timer = new DispatcherTimer();
this.timer.Tick += new EventHandler(OnTimerTick);
this.step = interval.Ticks;
}
TimeSpan GetTimerInterval()
{
var interval = nextTick - DateTime.Now.Ticks;
if (interval > 0)
{
return new TimeSpan(interval);
}
return TimeSpan.Zero; // yield
}
void OnTimerTick(object sender, EventArgs e)
{
if (DateTime.Now.Ticks >= nextTick)
{
n++;
if (Tick != null)
{
Tick(this, EventArgs.Empty);
}
nextTick += step;
}
var interval = GetTimerInterval();
Trace.WriteLine(interval);
timer.Interval = interval;
}
public void Reset()
{
n = 0;
nextTick = 0;
}
public void Start()
{
var now = DateTime.Now.Ticks;
nextTick = now + (step - (nextTick % step));
timer.Interval = GetTimerInterval();
timer.Start();
}
public void Stop()
{
timer.Stop();
nextTick = DateTime.Now.Ticks % step;
}
}
Create a method or put this code where you want the timer to start:
int time = 60 - DateTime.Now.Second; // Gets seconds to next minute
refreshTimer.Interval = time * 1000;
refreshTimer.Start();
And then on your tick event set the interval to 60000:
private void refreshTimer_Tick(object sender, EventArgs e)
{
refreshTimer.Interval = 60000; // Sets interval to 60 seconds
// Insert Refresh logic
}
By making use of ReactiveExtensions you could use the following code if you were interested in doing something as simple as printing to the console.
using System;
using System.Reactive.Linq;
namespace ConsoleApplicationExample
{
class Program
{
static void Main()
{
Observable.Interval(TimeSpan.FromMinutes(1))
.Subscribe(_ =>
{
Console.WriteLine(DateTime.Now.ToString());
});
Console.WriteLine(DateTime.Now.ToString());
Console.ReadLine();
}
}
}
Running a bit of code to see if the minute has changed once per second should not require much CPU time, and should be acceptable.
What about Quartz.NET? I think its a good framework to do timed actions.
You could set up two timers. An initial short interval timer (perhaps to fire every second, but dependent on how presice the second timer must fire on the minute).
You would fire the short interval timer only until the desired start time of the main interval timer is reached. Once the initial time is reached, the second main interval timer can be activated, and the short interval timer can be deactivated.
void StartTimer()
{
shortIntervalTimer.Interval = 1000;
mainIntervalTimer.Interval = 60000;
shortIntervalTimer.Tick +=
new System.EventHandler(this.shortIntervalTimer_Tick);
mainIntervalTimer.Tick +=
new System.EventHandler(mainIntervalTimer_Tick);
shortIntervalTimer.Start();
}
private void shortIntervalTimer_Tick(object sender, System.EventArgs e)
{
if (DateTime.Now.Second == 0)
{
mainIntervalTimer.Start();
shortIntervalTimer.Stop();
}
}
private void mainIntervalTimer_Tick(object sender, System.EventArgs e)
{
// do what you need here //
}
Alternatively, you could sleep to pause execution until it times out which should be close to your desired time. This will only wake the computer when the sleep finishes so it'll save you CPU time and let the CPU power down between processing events.
This has the advantage of modifying the timeout so that it will not drift.
int timeout = 0;
while (true) {
timeout = (60 - DateTime.Now.Seconds) * 1000 - DateTime.Now.Millisecond;
Thread.Sleep(timeout);
// do your stuff here
}
Use a timer set to run every second (or millisecond, whatever your accuracy threshold is), and then code the method to run your functionality if and only if the current time is within that threshold past the "on the minute" point.
What I'm using for scheduled tasks is a System.Threading.Timer(System.Threading.TimerCallback, object, int, int) with the callback set to the code I want to execute based on the interval which is supplied in milliseconds for the period value.
What about a combination of aquinas' answer and 'polling': (apologies for the mixture of languages)
def waitForNearlyAMinute:
secsNow = DateTime.Now.Second;
waitFor = 55 - secsNow;
setupTimer(waitFor, pollForMinuteEdge)
def pollForMinuteEdge:
if (DateTime.Now.Second == 0):
print "Hello, World!";
waitForNearlyAMinute();
else:
setupTimer(0.5, pollForMinuteEdge)
I have a solution based on Environment.TickCount
static void Main(string[] args)
{
//constatnt total miliseconds to one minute
const Int32 minuteMilisecond = 60 * 1000;
//get actual datetime
DateTime actualDateTime = DateTime.UtcNow;
//compenzation to one minute
Int32 nexTimer = Environment.TickCount + ((59 - actualDateTime.Second) * 1000) + (999 - actualDateTime.Millisecond);
//random fuction to simulate different delays on thread
Random rnd = new Random();
//main loop
while (true)
{
if (Environment.TickCount > nexTimer)
{
nexTimer += minuteMilisecond;
//execute your code here every minute
Console.WriteLine($"actual DateTime: {DateTime.Now.ToString("yyyy.MM.dd HH:mm:ss:ffff")}");
}
//random sleep between 100 - 200 ms
Thread.Sleep(rnd.Next(100, 200));
}
}

Run once a day in C#

Is there any clever method out there to make my executeEveryDayMethod() execute once a day, without having to involve the Windows TaskScheduler?
I achieved this by doing the following...
Set up a timer that fires every 20 minutes (although the actual timing is up to you - I needed to run on several occasions throughout the day).
on each Tick event, check the system time. Compare the time to the scheduled run time for your method.
If the current time is less than the scheduled time, check a in some persistent storage to get the datetime value of the last time the method ran.
If the method last ran more than 24 hours ago, run the method, and stash the datetime of this run back to your data store
If the method last ran within the last 24 hours, ignore it.
HTH
*edit - code sample in C# :: Note : untested...
using System;
using System.Collections.Generic;
using System.Text;
using System.Timers;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
Timer t1 = new Timer();
t1.Interval = (1000 * 60 * 20); // 20 minutes...
t1.Elapsed += new ElapsedEventHandler(t1_Elapsed);
t1.AutoReset = true;
t1.Start();
Console.ReadLine();
}
static void t1_Elapsed(object sender, ElapsedEventArgs e)
{
DateTime scheduledRun = DateTime.Today.AddHours(3); // runs today at 3am.
System.IO.FileInfo lastTime = new System.IO.FileInfo(#"C:\lastRunTime.txt");
DateTime lastRan = lastTime.LastWriteTime;
if (DateTime.Now > scheduledRun)
{
TimeSpan sinceLastRun = DateTime.Now - lastRan;
if (sinceLastRun.Hours > 23)
{
doStuff();
// Don't forget to update the file modification date here!!!
}
}
}
static void doStuff()
{
Console.WriteLine("Running the method!");
}
}
}
Take a look at quartz.net. It is a scheduling library for .net.
More specifically take a look here.
If the time when it is run is not relevant and can be reset each time the program starts you can just set a timer, which is the easiest thing to do. If that's not acceptable it starts getting more complex, like the solution presented here and which still doesn't solve the persistence problem, you need to tackle that separately if you truly wish to do what Scheduled Tasks would. I'd really consider again if it's worth going through all the trouble to replicate a perfectly good existing functionality.
Here's a related question (Example taken from there).
using System;
using System.Timers;
public class Timer1
{
private static Timer aTimer = new System.Timers.Timer(24*60*60*1000);
public static void Main()
{
aTimer.Elapsed += new ElapsedEventHandler(ExecuteEveryDayMethod);
aTimer.Enabled = true;
Console.WriteLine("Press the Enter key to exit the program.");
Console.ReadLine();
}
// Specify what you want to happen when the Elapsed event is
// raised.
private static void ExecuteEveryDayMethod(object source, ElapsedEventArgs e)
{
Console.WriteLine("The Elapsed event was raised at {0}", e.SignalTime);
}
}
public partial class Main : Form
{
public Main( ) // Windows Form is called Main
{
InitializeComponent( );
}
private void Main_Load( object sender, EventArgs e )
{
/*
This example uses a System.Windows.Forms Timer
This code allows you to schedule an event at any given time in one day.
In this example the timer will tick at 3AM.
*/
Int32 alarm = GetAlarmInMilliseconds( 3, 0, 0 ); // Milliseconds until 3:00 am.
timer_MessageCount.Interval = alarm; // Timer will tick at 3:00am.
timer_MessageCount.Start( );
}
private Int32 GetAlarmInMilliseconds(Int32 eventHour, Int32 eventMinute, Int32 eventSecond )
{
DateTime now = DateTime.Now;
DateTime eventTime = new DateTime( now.Year, now.Month, now.Day, eventHour, eventMinute, eventSecond );
TimeSpan ts;
if ( eventTime > now )
{
ts = eventTime - now;
}
else
{
eventTime = eventTime.AddDays( 1 );
ts = eventTime - now;
}
Console.WriteLine("Next alarm in: {0}", ts );
return ( Int32 ) ts.TotalMilliseconds;
}
static void DoSomething( )
{
Console.WriteLine( "Run your code here." );
}
private void timer_MessageCount_Tick( object sender, EventArgs e )
{
DoSomething( );
Int32 alarm = GetAlarmInMilliseconds( 3, 0, 0 ); // Next alarm time = 3AM
timer_MessageCount.Interval = alarm;
}
}
Suppose you have the daily time in _Settings.DataCleanupTime in Format "hh:mm:ss"
//note the namespace, there are 4 different timers in .NET
System.Threading.Timer _Timer;
DateTime now = DateTime.Now;
//convert "hh:mm:ss" to three integers
var dateparts = _Settings.DataCleanupTime.Split(new char[] { ':' }).Select(p => Convert.ToInt32(p)).ToArray();
DateTime firstTime = new DateTime(now.Year, now.Month, now.Day, dateparts[0], dateparts[1], dateparts[2]);
//e.g. firsttime is today at 2am and it is already 6am
if(firstTime < now)
{
//first run will be tomorrow
firstTime = firstTime.AddDays(1);
}
int delay = Convert.ToInt32((firstTime - now).TotalMilliseconds);
_Timer = new Timer(DoWork, state:null, delay, 3600 * 24 * 1000);
The signature of DoWork is:
public void DoWork(Object state)
To stop the timer just call:
_Timer.Dispose();
You could query time and run if your within some time frame, that way even if the machine goes off you'll call the method or use a timer like Vinko's suggestion.
But the better solution (akin to older CRON versions, so its a proven pattern) is to have some persistent data, with the cheapest solution I can think of right now being a blank file, check its last modified attribute, and if it hasn't been modified within the last 24 hours you touch it and run your method. This way you assure the method gets run first thing in the case the application is out for the weekend for example.
I've done this in C# before, but its was a year ago at another Job, so I don't have the code but it was about 20 lines (with comments and all) or so.
To run the job once daily between 7 and 8pm, i set up a timer with interval = 3600000 ms and then just execute the following code for timer tick.
private void timer1_Tick(object sender, EventArgs e)
{
//ensure that it is running between 7-8pm daily.
if (DateTime.Now.Hour == 19)
{
RunJob();
}
}
An hour window is fine for me. Extra granularity on time will require a smaller interval on the timer (60000 for a minute) and including minutes on the if.
eg
{
//ensure that it is running at 7:30pm daily.
if (DateTime.Now.Hour == 19 && DateTime.Now.Minute == 30)
{
RunJob();
}
}
If you only want to run it once a day and don't care when, this will work (will run just after midnight).
Declare a DateTime variable:
DateTime _DateLastRun;
In your startup, set the initial date value:
_DateLastRun = DateTime.Now.Date;
In the logic area where you want to check whether to perform the action:
if (_DateLastRun < DateTime.Now.Date)
{
// Perform your action
_DateLastRun= DateTime.Now.Date;
}
You can try this solution.
public Main()
{
StartService();
}
public async Task StartService(CancellationToken token = default(CancellationToken))
{
while (!token.IsCancellationRequested)
{
ExecuteFunction();
try
{
await Task.Delay(TimeSpan.FromDays(1), token);
}
catch (TaskCanceledException)
{
break;
}
}
}
public async Task ExecuteFunction()
{
...
}
Here is how you can do it if you're running a Windows Forms Application. But you need to configure a setting so that you can store the last date the event was fired. If you never intend to close the app you can just store the date as a static value.
Im using a timer to fire the event, as following:
private void tmrAutoBAK_Tick(object sender, EventArgs e)
{
if (BakDB.Properties.Settings.Default.lastFireDate != DateTime.Now.ToString("yyyy-MM-dd"))
{
tmrAutoBAK.Stop(); //STOPS THE TIMER IN CASE OF EVENTUAL MESSAGEBOXES.
createBakup(); //EVENT
BakDB.Properties.Settings.Default.lastFireDate = DateTime.Now.ToString("yyyy-MM-dd"); //STORING CURRENT DATE TO SETTINGS FILE.
BakDB.Properties.Settings.Default.Save(); //SAVING THE SETTING FILE.
tmrAutoBAK.Start(); //RESTARTING TIMER
}
}
This is my very simple solution to execute a method once once a day:
private static DateTime _LastAccessedTime;
private static void OnceADayCode() // method that you want access once a day
{
_LastAccessedTime = DateTime.Today;
}
public static void PublicMethod() // this can be a method called from outside
{
if (_LastAccessedTime != DateTime.Today)
{
OnceADayCode();
}
}
with the same logic you can also use:
private static DateTime _LastAccessedTime;
private static void OnceADayCode()
{
if (_LastAccessedTime.Today != DateTime.Today)
{
// code that you want access once a day
_LastAccessedTime = DateTime.Today;
}
}

Categories