How to call Async method from ElapsedEventHandler

I am going to use the Windows service to send Telegram messages periodically (every two minutes). My Windows service will start working normally, and after 2 minutes it will stop. I checked my code and found out that this is due to asynchrony. How can i solve the problem?

protected override void OnStart(string[] args) { //< I declared a System.Timers.Timer to send new Telegram messages. aTimer = new System.Timers.Timer(120000); // 2 minutes aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent); aTimer.Enabled = true; GC.KeepAlive(aTimer); //> } private static void OnTimedEvent(object source, ElapsedEventArgs e) { SendNewMessages(); } async static void SendNewMessages() { MyDataContext myDB = new MyDataContext(); var newMessages = myDB.TelegramMessages.Where(tm => tm.Status != "New Message"); foreach (TelegramMessage newMessage in newMessages) { try { var store = new FileSessionStore(); var client = new TelegramClient(store, "MySession"); await client.Connect(); var res = await client.ImportContactByPhoneNumber(newMessage.ReceiverPhoneNumber); await client.SendMessage(res.Value, newMessage.Message); newMessage.Status = "Sent"; myDB.SubmitChanges(); } catch (Exception ex) { newMessage.Status = ex.Message; myDB.SubmitChanges(); } Thread.Sleep(5000); } } 
+2
source share
1 answer

The only thing I see directly is that async / await was not fully implemented before the event handler, since "SendNewMessages" returns void. And your event handler is not asynchronous.

According to MSDN in the section "Async return types (C # and Visual Basic)"

The main use of the void return type (helper routines in Visual Basic) refers to event handlers where the void return type is required. The void return can also be used to override the void return methods or for methods that perform actions that can be classified as fire and forget.

This is most likely a problem in your scenario, so you can try changing your SendNewMessage to this

 async static Task SendNewMessages() 

And your event handler for this

 private async static void OnTimedEvent(object source, ElapsedEventArgs e) { await SendNewMessages(); } 

UPDATED

It would also be nice to add some error handling code to your SendNewMessages method, since if an exception is thrown, your service will close.

 async static Task SendNewMessages() { try { ... Your code here } catch(Exception e) { ... exceptionhandling here } } 

At the moment, you only have exception handling in your foreach, but you do not have error handling (as far as I can see) for your database code.

if an exception is thrown here

 MyDataContext myDB = new MyDataContext(); var newMessages = myDB.TelegramMessages.Where(tm => tm.Status != "New Message"); foreach (TelegramMessage newMessage in newMessages) 

or here:

 newMessage.Status = ex.Message; myDB.SubmitChanges(); 

Service will end

+1
source

All Articles