Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/date/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用async/await时我的控制台应用程序过早关闭?_C#_Multithreading_Mailkit - Fatal编程技术网

C# 使用async/await时我的控制台应用程序过早关闭?

C# 使用async/await时我的控制台应用程序过早关闭?,c#,multithreading,mailkit,C#,Multithreading,Mailkit,我有一个控制台应用程序,它所做的就是循环所有客户,向特定客户发送电子邮件,然后关闭。我注意到MailKit中的一些函数提供异步功能,所以我尝试使用它们而不是非aysnc,当我这样做时,它在上执行了第一条语句(emailClient.ConnectAsync),然后我注意到我的控制台应用程序正在关闭。它没有坠毁。执行返回到Main()并在调用my SendReports()函数后继续执行 private static void Main(string[] args) { ... var r

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

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

  reportServices.SendReportsToCustomers();

  Log.CloseAndFlush();  // It executes the first await call then returns here.
}

internal class ReportsServices
{
  public async void SendReportsToCustomers()
  {
    try
    {
      foreach (var customer in _dbContext.Customer)
      {
          ...
          await SendReport(customer.Id, repTypeId, freqName);
      }
    }
    catch (Exception e)
    {
      Console.WriteLine(e);
      throw;
    }
  }

  private async Task SendReport(int customerId, int repTypeId, string freqName)
  {
    try
    {
      ...
        var es = new EmailSender();
        await es.SendAsync();
      }
    }
    catch (Exception e)
    {
      Console.WriteLine(e);
      throw;
    }

  }
}

public class EmailSender
{
  public async Task SendAsync()
  {
    try
    {
      var message = new MimeMessage();

      ...

      using (var emailClient = new SmtpClient())
      {
        await emailClient.ConnectAsync("smtp.gmail.net", 587);  
        await emailClient.AuthenticateAsync("username", "password"); // If I put a debug break here, it doesn't hit.
        await emailClient.SendAsync(message);
        await emailClient.DisconnectAsync(true);

       // If I use the following calls instead, my console app will not shutdown until all the customers are sent emails.

await emailClient.Connect("smtp.gmail.net", 587);  
await emailClient.Authenticate("username", "password"); // If I put a debug break here, it doesn't hit.
await emailClient.Send(message);
await emailClient.Disconnect(true);

      }
    }
    catch (Exception e)
    {
      Console.WriteLine(e);
      throw;
    }

  }
}
我不明白的是,为什么我的循环不能继续在所有客户之间循环还有更多的工作要做。不知道为什么会跳回到主函数

我所希望的是,循环将继续通过所有客户发送电子邮件;不必等待电子邮件发送后再继续下一封

我感谢你的帮助

我所希望的是,这种循环会一直持续下去 客户和发送电子邮件;不必等待电子邮件发送 在继续下一步之前

你的循环没有这样做。它实际上是一次发一封电子邮件。但是,调用线程正在立即获得控制权

下面这一行实际上是“在另一个线程上执行此操作,完成后继续运行此方法”。同时,由于
await
没有阻塞,因此调用线程继续执行

await SendReport(customer.Id, repTypeId, freqName);
我建议这样做,启动所有报告并执行
等待
完成所有报告:

await Task.WhenAll(_dbContext.Customer.Select(x => SendReport(x.Id, repTypeId, freqName));
我还强烈建议在使用
async
时始终返回
任务

public async Task SendReportsToCustomers()
这样,调用者就可以
等待
,或者对返回值做任何它想做的事情。您甚至可以使用
Task.Result
对其进行阻止

我不明白的是为什么我的循环不能继续在所有的地方循环 顾客还有更多的工作要做。不知道为什么会跳过 回到主功能

请参阅
wait
,以更好地了解它的用法和非阻塞性


在一个非常高的层次上,您可以将
await
想象为“在任务完成之前不要执行此方法的其余部分,但也不要阻止它”。

您似乎不理解
await
的工作原理。每次对函数调用
wait
,调用方函数本身都会临时返回,直到等待的函数返回

这意味着,除非等待的函数及时返回,否则主线程将完成执行
main
,并退出应用程序。要解决此问题,您需要将
SendReportsToCustomers()
的返回类型更改为类似以下内容:

public async Task SendReportsToCustomers()
现在,你可以等它完成了。以阻塞方式:

reportServices.SendReportsToCustomers().Result();

或者在使用
等待
的非阻塞等待中:

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

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

专用静态异步任务主(字符串[]args)
{
...
var reportServices=new reports服务();
等待reportServices.SendReportsToCustomers();
Log.CloseAndFlush();//它执行第一个等待调用,然后返回此处。
}
如果没有,则必须同步等待操作完成:

private static void Main(字符串[]args)
{
...
var reportServices=new reports服务();
reportServices.SendReportsToCustomers().Wait();;
Log.CloseAndFlush();//它执行第一个等待调用,然后返回此处。
}

这里有一个更详细的解释。

正如其他人所解释的,控制台应用程序不会等待异步方法完成。它将直接跳到下一行代码。如果它到达您的主要功能的末尾,控制台应用程序将结束


也许您可以在主功能的末尾添加一个
Console.ReadLine()
,以防止控制台应用程序突然终止。

是非阻塞的。调用线程继续并行运行,而不是方法的其余部分。调用
SendReportsToCustomers
的任何程序都不能
等待它,因为它不会返回
任务。如果您想阻止使用
任务.Result
我仍在努力解决这个问题
我建议先从my开始,然后再从my开始。忽略SendReport(任务
的返回值)不是很好的做法或设计。您的意思是使用
任务.Wait()
不是很好的做法?您想详细说明一下吗?您的foreach循环正在调用
SendReport
并忽略返回值。您只是从中删除了
wait
。但为什么这很重要?使用
如何选择
任务。所有
何时实际处理返回值?因为我使用
等待
。。。链接
异步
方法背后的思想是链接
等待
调用。或者,至少对返回的
任务执行一些操作。你完全忽略了它。充其量这是一个糟糕的设计。最坏的情况是一只虫子。这正是您应该避免声明为
async void
的方法的原因。我实现了该方法,它成功了。感谢问题:为什么现在要等待SendReportToCustomers完成后才能继续?我认为它会继续并关闭应用程序。
await reportServices.SendReportsToCustomers();