How to Call an Async Method from within ElapsedEventHandler

怎甘沉沦 提交于 2019-12-24 00:28:16

问题


I'm going to use a Windows Service to send Telegram Messages periodically (Every two minutes). My Windows Service starts fine and after 2 minutes it is stopped. I checked my code and find out it is because of async. 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);
    }
}

回答1:


One thing I see directly is that async/await has not been implemented all the way to the eventhandler since "SendNewMessages" returns void. And your eventhandler is not async.

According to MSDN on "Async Return Types (C# and Visual Basic)"

The primary use of the void return type (Sub procedures in Visual Basic) is in event handlers, where a void return type is required. A void return also can be used to override void-returning methods or for methods that perform activities that can be categorized as "fire and forget."

This is most likely an issue in your scenario, so you could try changing your SendNewMessage to this

async static Task SendNewMessages()

And your eventhandler to this

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

UPDATED

It would also be a good idea to add some errorhandling code to your "SendNewMessages"-method since if an exception is thrown, your service will quit.

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

At the moment you only have exceptionhandling within your foreach, but you do not have any errorhandling (as far as I can see) for your database-code.

if an exception is throw 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();

The service would end



来源:https://stackoverflow.com/questions/36661338/how-to-call-an-async-method-from-within-elapsedeventhandler

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!