我正在开发一个MVC C#网站,.NET 4.0,在一个控制器中,我需要发送大量邮件。 我从一个独立程序复制了我自己的代码,我使用SendAsynch传递一个回调。 在stanalone应用程序中一切正常。
当然,在控制器中,相同的代码不起作用:永远不会调用回调。
有人可以告诉我为什么相同的代码独立运行而不是在控制器中?
这是主要代码:
SmtpClient GenMailClient = new SmtpClient();
GenMailClient.SendCompleted += SendCompleted;
GenMailClient.SendAsync(message, ArgumentForTheCallBack);
WaitingMails++;
var startTime = DateTime.Now;
//waits until the SendCompleted is called (FOREVER!)
while (WaitingMails != 0)
Thread.Sleep(500);
GenMailClient.Dispose();
这是SendCompleted回调:
private void SendCompleted(object sender, AsyncCompletedEventArgs e)
{
WaitingMails--;
}
答案 0 :(得分:1)
这是因为SmtpClient.SendAsync
捕获当前SynchronizationContext
并在捕获的上下文(如果有)上执行回调(SendCompleted
)。
在asp.net mvc(非核心)中 - 每个请求都有相应的同步上下文。您可以通过
来阻止与该上下文对应的线程while (WaitingMails != 0)
Thread.Sleep(500);
这不会导致SendCompleted
回调执行,因为相应的线程被阻止,并且它被阻止等待SendComplete
执行,所以你有经典的死锁场景。
最简单的解决方法是忘记SendAsync
和SendCompleted
并使用async\await
的{{1}}功能:
SmtpClient
当然,你必须在异步的时候重写你的asp.net mvc动作(至少那些发送电子邮件的动作)。如果您不想这样做,另一种解决方案是:
SmtpClient GenMailClient = new SmtpClient();
await GenMailClient.SendMailAsync(message);
// done
因为您尝试做的是使用异步方法模拟同步发送。为什么?只需同步发送即可。