Async with a Timer - c#

I'm updating my code to use Async, the issue is that to Timer.Elapsed requires a void return type, but this basically doesn't allow for an await, so the code doesn't wait and finishes too soon before everything is done.
Code:
public static void Main(string[] args)
{
Timer timer;
timer = new System.Timers.Timer();
timer.Interval = 3000;
timer.Elapsed += OnTimerAsync;
timer.Enabled = true;
timer.Start();
Console.WriteLine("Press the Enter key to exit the program... ");
Console.ReadLine();
Console.WriteLine("Terminating the application...");
}
public async static void OnTimerAsync(object sender, ElapsedEventArgs args)
{
await ExecuteWorkflowAsync();
}
private async static Task<bool> ExecuteWorkflowAsync()
{
List<Schedule> schedulesToRun;
try
{
await JobLoader.LoadAsync(schedulesToRun);
}
catch (Exception ex)
{
// Log ex
}
return true;
}
Is there a way to use the Timer object with Async?

Try this:
public async static void OnTimerAsync(object sender, ElapsedEventArgs args)
{
timer.Enabled = false;
await ExecuteWorkflowAsync();
timer.Enabled = true;
}

Related

WPF non blocking UI Popup

In an Office Add-In I need to call a WPF which executes a function which may timeout but I want the UI to be responsive to allow the user to click the cancel/close button.
So far my code is the following:
// From the Ribbon
var f = new Forms.CheckConnectivityPopup();
f.doneEvent.WaitOne();
// Get the status from the popup or null if the operation was cancelled
var status = f.status;
if(status != null)
// Continue the execution
--------------------------------
public partial class CheckConnectivityPopup : MetroWindow
{
public readonly BackgroundWorker worker = new BackgroundWorker();
public AutoResetEvent doneEvent = new AutoResetEvent(false);
public Status status = null;
public CheckConnectivityPopup()
{
InitializeComponent();
this.Show();
worker.DoWork += worker_DoWork;
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
worker.RunWorkerAsync();
}
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
// displayAndCheck();
status = CheckStatus();
Thread.Sleep(10000); // to simulate the time
}
private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
doneEvent.Set();
this.Close();
}
}
So far the popup is frozen until sleep period is completed.
WaitOne() blocks the current thread. You could replace the AutoResetEvent with a SemaphoreSlim:
public partial class CheckConnectivityPopup : MetroWindow
{
public readonly BackgroundWorker worker = new BackgroundWorker();
public SemaphoreSlim doneEvent = new SemaphoreSlim(0, 1);
public Status status = null;
public CheckConnectivityPopup()
{
InitializeComponent();
this.Show();
worker.DoWork += worker_DoWork;
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
worker.RunWorkerAsync();
}
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
//displayAndCheck();
status = CheckStatus();
Thread.Sleep(10000); // to simulate the time
}
private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
doneEvent.Release();
this.Close();
}
}
...that you can await asynchronously:
var f = new Forms.CheckConnectivityPopup();
await f.doneEvent.WaitAsync();
For you to be able to await the WaitAsync() method, you must mark the method where you create the instance of the CheckConnectivityPopup as async:
void async YourMethod() { ... }
If this is not an option for some reason, you could use the ContinueWith method instead:
var f = new Forms.CheckConnectivityPopup();
f.doneEvent.WaitAsync().ContinueWith(_ =>
{
var status = f.status;
if (status != null)
{
//...
}
});

Best way to run a background task with timer

The following code run a task which check, each 5 seconds, the status of a database. I had to use the BeginInvoke but I'm not sure is the best way to do:
public btnDatabaseStatus()
{
InitializeComponent();
if (!DesignerProperties.GetIsInDesignMode(this))
Global.LM.SetTraduzioniWindow(this);
Init();
DispatcherOperation dbStatDispatcher = null;
try
{
dbStatDispatcher = App.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() =>
{
Timer timer = new Timer(5000);
timer.Elapsed += OnTimedEvent;
timer.Enabled = true;
}));
}
catch (Exception ex)
{
if (dbStatDispatcher != null) dbStatDispatcher.Abort();
}
}
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
if (App.Current!=null) App.Current.Dispatcher.BeginInvoke(new Action(() => { IsDbConnected = Dbs[0].IsConnected; }));
}
private void Init()
{
Dbs = null;
Dbs = Global.DBM.DB.Values.Where(d => d.IsExternalDB).ToList();
lstvDatabase.ItemsSource = Dbs;
}
I'm afraid concerning the closing of main application as sometimes the Dispatcher is null. Any hints to improve the code?
Forget about Dispatcher.BeginInvoke and System.Threading.Timer.
Use a WPF DispatcherTimer:
public btnDatabaseStatus()
{
InitializeComponent();
var timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(5) };
timer.Tick += OnTimerTick;
timer.Start();
}
private void OnTimerTick(object sender, EventArgs e)
{
IsDbConnected = Dbs[0].IsConnected;
}
Or shorter:
public btnDatabaseStatus()
{
InitializeComponent();
var timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(5) };
timer.Tick += (s, e) => IsDbConnected = Dbs[0].IsConnected;
timer.Start();
}
If the Tick handler is supposed to do some long-running task, you may declare it async:
private async void OnTimerTick(object sender, EventArgs e)
{
await SomeLongRunningMethod();
// probably update UI after await
}

Rerun service every x min with timer not working

I have a service that I want to run every X min using (for example) a timer.
This is not working, why? Any better way I can do this? Tried searching and didn't found anything that worked for me...The breakpoint never hits OnStop method...
static void Main()
{
WriteLine("service has started");
timer = new Timer();
timer.Enabled = true;
timer.Interval = 1000;
timer.AutoReset = true;
timer.Start();
timer.Elapsed += scheduleTimer_Elapsed;
}
private static void scheduleTimer_Elapsed(object sender, ElapsedEventArgs e)
{
WriteLine("service is runs again");
}
public static void WriteLine(string line)
{
Console.WriteLine(line);
}
I was in a bit same situation earlier. I used the following code, it worked for me.
// The main Program that invokes the service
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main()
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new Service1()
};
ServiceBase.Run(ServicesToRun);
}
}
//Now the actual service
public partial class Service1 : ServiceBase
{
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
///Some stuff
RunProgram();
///////////// Timer initialization
var scheduleTimer = new System.Timers.Timer();
scheduleTimer.Enabled = true;
scheduleTimer.Interval = 1000;
scheduleTimer.AutoReset = true;
scheduleTimer.Start();
scheduleTimer.Elapsed += new ElapsedEventHandler(scheduleTimer_Elapsed);
}
protected override void OnStop()
{
}
void scheduleTimer_Elapsed(object sender, ElapsedEventArgs e)
{
RunProgram();
}
//This is where your actual code that has to be executed multiple times is placed
void RunProgram()
{
//Do some stuff
}
}

Timer is not processing

I create a windows service to run a piece of code and implemented timer in it to run it periodically.
My timer class is :
class TimerClass
{
private static System.Timers.Timer aTimer;
public static void Main()
{
aTimer = new System.Timers.Timer(1000);
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
aTimer.Interval = 5000;
aTimer.Enabled = true;
GC.KeepAlive(aTimer);
}
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
aTimer.Stop();
DatabaseUpdation dbUp = new DatabaseUpdation();
File.AppendAllText(#"C:\Documents and Settings\New Folder\My Documents\demo\abc.txt", "Start" + " " + DateTime.Now.ToString() + Environment.NewLine);
dbUp.GetDatafromSource();
aTimer.Start();
}
}
And i am calling it from my Start method:
protected override void OnStart(string[] args)
{
TimerClass timer = new TimerClass();
}
But timer is not executing at all.
Can anyone find me the mistake here?
Thanks in advance
Please, read about Constructor
your initialization code should not be in public static void Main(), but instead in public TimerClass()
class TimerClass
{
private System.Timers.Timer aTimer;
public TimerClass()
{
aTimer = new System.Timers.Timer(1000);
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
aTimer.Interval = 5000;
aTimer.Enabled = true;
GC.KeepAlive(aTimer);
}
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
aTimer.Stop();
DatabaseUpdation dbUp = new DatabaseUpdation();
File.AppendAllText(#"C:\Documents and Settings\New Folder\My Documents\demo\abc.txt", "Start" + " " + DateTime.Now.ToString() + Environment.NewLine);
dbUp.GetDatafromSource();
aTimer.Start();
}
}
also your methods and aTimer should not be static.
You need to call Main method to start timer:
protected override void OnStart(string[] args)
{
TimerClass.Main();
}
BTW not very good name - I think something like Start will be better. Also I hope this is not your app entry point method.
You forgot to start your timer. Move it outside your elapse. Elapse is only called when your timer is expired.
aTimer.Start();
FYI you don't need to enable your timer once you call the start method
Try this:
class TimerClass
{
private static System.Timers.Timer aTimer;
public static void Main()
{
aTimer = new System.Timers.Timer(1000);
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
aTimer.Interval = 5000;
GC.KeepAlive(aTimer);
}
public static void Start()
{
aTimer.Start();
}
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
aTimer.Stop();
DatabaseUpdation dbUp = new DatabaseUpdation();
File.AppendAllText(#"C:\Documents and Settings\New Folder\My Documents\demo\abc.txt", "Start" + " " + DateTime.Now.ToString() + Environment.NewLine);
dbUp.GetDatafromSource();
aTimer.Start();
}
}
and you need to call it like this:
protected override void OnStart(string[] args)
{
//TimerClass timer = new TimerClass();<==No need it's static class!!!
TimerClass.Main();
TimerClass.Start();
}

Event Handler Problem in Windows Service

I am going nuts. I can't figure out the problem.
I have a windows service that has a simple timer method. If I start the service, it always gives out exception at onTimerElapsed event. But If I write my XMLOperation methods in a different method(but not timer which I only need) and call it from program.cs, it works just fine. The working code is at the bottom also.
partial class DatabaseService : ServiceBase
{
Timer timer = new Timer();
public DatabaseService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
timer.Interval = 10000;
timer.Enabled = true;
timer.Elapsed += new ElapsedEventHandler(onElapsedTime);
timer.Start();
}
protected override void OnStop()
{
timer.Enabled = false;
}
public void onElapsedTime(object source, ElapsedEventArgs e)
{
try
{
XMLOperations operation = new XMLOperations();
operation.WebServiceFlexiCampaigns("http://www.flexi.com.tr/data/xml/pazaryeri/mobil.xml");
operation.WebServiceShopMilesCampaignsXMLRead("http://www.shopandmiles.com/xml/3_119_3.xml");
operation.WebServiceBonusCampaignsXMLRead("http://www.bonus.com.tr/apps/getcampaignxml.aspx?type=campaigns");
}
catch (Exception ex)
{
StreamWriter SW;
SW = File.CreateText("c:\\1.txt");
SW.WriteLine(ex.Message);
SW.Close();
}
}
here is the working one, but this time I could not manage to work that code in periods of time like I can do in timer event. I call test method manually from program.cs
partial class DatabaseService : ServiceBase
{
Timer timer = new Timer();
public DatabaseService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
timer.Interval = 10000;
timer.Enabled = true;
timer.Elapsed += new ElapsedEventHandler(onElapsedTime);
timer.Start();
}
protected override void OnStop()
{
timer.Enabled = false;
}
public void test()
{
try
{
XMLOperations operation = new XMLOperations();
operation.WebServiceFlexiCampaigns("http://www.flexi.com.tr/data/xml/pazaryeri/mobil.xml");
operation.WebServiceShopMilesCampaignsXMLRead("http://www.shopandmiles.com/xml/3_119_3.xml");
operation.WebServiceBonusCampaignsXMLRead("http://www.bonus.com.tr/apps/getcampaignxml.aspx?type=campaigns");
}
catch (Exception ex)
{
StreamWriter SW;
SW = File.CreateText("c:\\1111.txt");
SW.WriteLine(ex.Message);
SW.Close();
}
}
You can try this thread (see SamAgain response):
http://social.msdn.microsoft.com/Forums/en/clr/thread/8fbca78b-5078-4a12-8abb-4051076febbb
Hope it will work.

Categories

Resources