У меня есть действие, которое отправляет простое электронное письмо:
[HttpPost, ActionName("Index")]
public ActionResult IndexPost(ContactForm contactForm)
{
if (ModelState.IsValid)
{
new EmailService().SendAsync(contactForm.Email, contactForm.Name, contactForm.Subject, contactForm.Body, true);
return RedirectToAction(MVC.Contact.Success());
}
return View(contactForm);
}
И служба электронной почты:
public void SendAsync(string fromEmail, string fromName, string subject, string body, bool isBodyHtml)
{
MailMessage mailMessage....
....
SmtpClient client = new SmtpClient(settingRepository.SmtpAddress, settingRepository.SmtpPort);
client.EnableSsl = settingRepository.SmtpSsl;
client.Credentials = new NetworkCredential(settingRepository.SmtpUserName, settingRepository.SmtpPassword);
client.SendCompleted += client_SendCompleted;
client.SendAsync(mailMessage, Tuple.Create(client, mailMessage));
}
private void client_SendCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
Tuple<SmtpClient, MailMessage> data = (Tuple<SmtpClient, MailMessage>)e.UserState;
data.Item1.Dispose();
data.Item2.Dispose();
if (e.Error != null)
{
}
}
Когда я отправляю электронное письмо, я использую метод Async, тогда мой метод SendAsync возвращает сразу же, затем RedirectToAction называется. Но ответ (в данном случае перенаправление) не отправляется ASP.NET до завершения client_SendCompleted.
Вот что я пытаюсь понять:
При просмотре выполнения в отладчике Visual Studio SendAsync возвращает немедленно (и вызывается RedirectToAction), но в браузере ничего не происходит, пока не будет отправлено электронное письмо?
Если я поставлю точку останова внутри client_SendCompleted, клиент останется при загрузке ... пока я не нажму F5 в отладчике.
Это по замыслу. ASP.NET будет автоматически ожидать завершения любой незавершенной асинхронной работы, прежде чем завершить запрос, если асинхронная работа была запущена таким образом, что вызывается базовый SynchronizationContext . Это делается для того, чтобы ваша асинхронная операция пыталась взаимодействовать с HttpContext , HttpResponse и т. Д., Она все равно будет работать.
Если вы хотите сделать настоящий огонь и забудьте, вам нужно обернуть ваш вызов в ThreadPool.QueueUserWorkItem
. Это заставит его работать в новом потоке пула потоков, не проходя через SynchronizationContext , поэтому запрос будет благополучно возвращен.
Тем не менее, обратите внимание, что если по какой-либо причине домен приложения отключился, когда отправка еще продолжалась (например, если вы изменили файл web.config, поместили новый файл в bin, пул приложений был переработан и т. Д.) ) ваша асинхронная отправка будет внезапно прервана. Если вы заботитесь об этом, взгляните на Phil Haacks WebBackgrounder для ASP.NET , который позволяет вам ставить в очередь и выполнять фоновую работу (например, отправку электронной почты) таким образом, чтобы убедитесь, что он корректно завершает работу в случае закрытия домена приложения.
С помощью .Net 4.5.2 вы можете сделать это с помощью ActionMailer.Net
:
var mailer = new MailController();
var msg = mailer.SomeMailAction(recipient);
var tcs = new TaskCompletionSource<MailMessage>();
mailer.OnMailSentCallback = tcs.SetResult;
HostingEnvironment.QueueBackgroundWorkItem(async ct =>
{
msg.DeliverAsync();
await tcs.Task;
Trace.TraceInformation("Mail sent to " + recipient);
});
Сначала прочтите это: http: //www.hanselman. ком / блог / HowToRunBackgroundTasksInASPNET.aspx