如何在ElapsedEventHandler中调用异步方法

3

我打算使用Windows服务定期(每两分钟)发送Telegram消息。我的Windows服务启动良好,但在2分钟后停止了。我检查了我的代码并发现这是由于异步操作引起的。我该如何解决这个问题?

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

我检查了我的代码并发现是由于异步操作引起的。但我对此表示怀疑。我建议将其缩减为最小可重现示例,我怀疑实际问题可能是其他原因导致的,例如未处理的异常。 - Stephen Cleary
1个回答

3

我直接看到的一件事是,由于"SendNewMessages"返回void,因此async/await并没有完全实现到事件处理程序。而且你的事件处理程序不是async。

根据MSDN关于"C#和Visual Basic中的异步返回类型"的说明

void返回类型(在Visual Basic中为Sub过程)的主要用途是在事件处理程序中,其中需要void返回类型。void返回类型还可用于覆盖返回void的方法或执行可归类为“fire and forget”的活动的方法。

这很可能是你场景中的问题,所以你可以尝试将SendNewMessage更改为以下内容

async static Task SendNewMessages()

并将您的事件处理程序添加到此处

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

更新

另外,为您的“SendNewMessages”方法添加一些错误处理代码是一个好主意,因为如果抛出异常,您的服务将退出。

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

目前你的foreach循环中只有异常处理,但是在你的数据库代码中(据我所见)没有任何错误处理。

如果在这里抛出异常

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

foreach (TelegramMessage newMessage in newMessages)

或者在这里:

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

这项服务将会结束


我按照你的建议修改了代码,但在调用await SendNewMessages()后,Windows服务停止了。 - Mohsen
我正在等待回复。任何答案都将不胜感激。 - Mohsen
1
@MohsenJafari 我会在进一步调查后更新答案。 - Shazi
1
@MohsenJafari 我更新了我的答案,建议你开始寻找异常。 - Shazi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接