SmtpClient SendAsync никогда не вызывает обратный вызов SendCompleted - PullRequest
0 голосов
/ 28 мая 2018

Я работаю на веб-сайте 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--;
}

1 Ответ

0 голосов
/ 28 мая 2018

Это потому, что SmtpClient.SendAsync захватывает текущий SynchronizationContext и выполняет обратный вызов (SendCompleted) в этом захваченном контексте, если таковой имеется.

В asp.net mvc (не основной) - каждый запрос имеет соответствующий контекст синхронизации.Вы блокируете поток, соответствующий этому контексту, с помощью

while (WaitingMails != 0)
    Thread.Sleep(500);

. Это не дает возможности для выполнения обратного вызова SendCompleted, потому что соответствующий поток заблокирован, и он заблокирован, ожидая выполнения SendComplete, поэтому у вас есть классическийСценарий тупиковой ситуации.

Самое простое решение, с которым можно справиться, это забыть о SendAsync и SendCompleted и использовать async\await возможности SmtpClient:

SmtpClient GenMailClient = new SmtpClient();
await GenMailClient.SendMailAsync(message);
// done

Конечно, для этого выпридется переписать ваши действия asp.net mvc (по крайней мере, те, которые отправляют электронные письма) в асинхронном режиме.Если вы не хотите этого делать, другое решение:

SmtpClient GenMailClient = new SmtpClient();
GenMailClient.Send(message);

Потому что вы пытаетесь эмулировать синхронную отправку с помощью асинхронных методов.Зачем?Просто отправьте это синхронно.

...