使用异步/等待时我的控制台应用程序过早关闭?

PKo*_*ant 1 c# multithreading mailkit

我有一个控制台应用程序,它所做的就是循环所有客户并向特定客户发送电子邮件,然后关闭。我注意到 MailKit\xe2\x80\x99s 中的一些函数提供异步功能,因此我尝试使用它们而不是非 aysnc,当我这样做时,它执行了第一个语句 (emailClient.ConnectAsync),然后我注意到我的控制台应用程序正在关闭。它没有\xe2\x80\x99t崩溃。在调用 SendReports() 函数后,执行返回到 Main() 并继续执行。

\n\n
private static void Main(string[] args)\n{\n  ...\n  var reportServices = new ReportsServices();\n\n  reportServices.SendReportsToCustomers();\n\n  Log.CloseAndFlush();  // It executes the first await call then returns here.\n}\n\ninternal class ReportsServices\n{\n  public async void SendReportsToCustomers()\n  {\n    try\n    {\n      foreach (var customer in _dbContext.Customer)\n      {\n          ...\n          await SendReport(customer.Id, repTypeId, freqName);\n      }\n    }\n    catch (Exception e)\n    {\n      Console.WriteLine(e);\n      throw;\n    }\n  }\n\n  private async Task SendReport(int customerId, int repTypeId, string freqName)\n  {\n    try\n    {\n      ...\n        var es = new EmailSender();\n        await es.SendAsync();\n      }\n    }\n    catch (Exception e)\n    {\n      Console.WriteLine(e);\n      throw;\n    }\n\n  }\n}\n\npublic class EmailSender\n{\n  public async Task SendAsync()\n  {\n    try\n    {\n      var message = new MimeMessage();\n\n      ...\n\n      using (var emailClient = new SmtpClient())\n      {\n        await emailClient.ConnectAsync("smtp.gmail.net", 587);  \n        await emailClient.AuthenticateAsync("username", "password"); // If I put a debug break here, it doesn\'t hit.\n        await emailClient.SendAsync(message);\n        await emailClient.DisconnectAsync(true);\n\n       // If I use the following calls instead, my console app will not shutdown until all the customers are sent emails.\n\nawait emailClient.Connect("smtp.gmail.net", 587);  \nawait emailClient.Authenticate("username", "password"); // If I put a debug break here, it doesn\'t hit.\nawait emailClient.Send(message);\nawait emailClient.Disconnect(true);\n\n      }\n    }\n    catch (Exception e)\n    {\n      Console.WriteLine(e);\n      throw;\n    }\n\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

我不明白的是为什么我的循环不能继续循环所有客户?- 还有更多的工作要做。不知道为什么它会跳回主函数。

\n\n

我所希望的是,循环将继续通过所有客户并发送电子邮件;无需等待电子邮件发送即可继续下一封。

\n\n

我感谢您的帮助!

\n

You*_*BIH 5

首先,您应该避免async void 方法,ReportsServices.SendReportsToCustomers()应该 return Task。您的代码调用该方法,但不等待它完成,该方法是异步的,因此它在第一个等待时返回。您应该在 Main() 中等待它完成。有两种方法可以做到这一点:

如果您使用 C# 7,则允许使用 async Main:

private static async Task Main(string[] args)
{
  ...
  var reportServices = new ReportsServices();

  await reportServices.SendReportsToCustomers();

  Log.CloseAndFlush();  // It executes the first await call then returns here.
}
Run Code Online (Sandbox Code Playgroud)

如果没有,您将必须同步等待操作完成:

private static void  Main(string[] args)
{
  ...
  var reportServices = new ReportsServices();

  reportServices.SendReportsToCustomers().Wait();;

  Log.CloseAndFlush();  // It executes the first await call then returns here.
}
Run Code Online (Sandbox Code Playgroud)

这是一篇有进一步解释的文章