SmtpClient.SendAsync блокирует мой запрос ASP.NET MVC

У меня есть действие, которое отправляет простое электронное письмо:

    [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 в отладчике.

23
задан justSteve 8 August 2012 в 15:27
поделиться

2 ответа

Это по замыслу. ASP.NET будет автоматически ожидать завершения любой незавершенной асинхронной работы, прежде чем завершить запрос, если асинхронная работа была запущена таким образом, что вызывается базовый SynchronizationContext . Это делается для того, чтобы ваша асинхронная операция пыталась взаимодействовать с HttpContext , HttpResponse и т. Д., Она все равно будет работать.

Если вы хотите сделать настоящий огонь и забудьте, вам нужно обернуть ваш вызов в ThreadPool.QueueUserWorkItem. Это заставит его работать в новом потоке пула потоков, не проходя через SynchronizationContext , поэтому запрос будет благополучно возвращен.

Тем не менее, обратите внимание, что если по какой-либо причине домен приложения отключился, когда отправка еще продолжалась (например, если вы изменили файл web.config, поместили новый файл в bin, пул приложений был переработан и т. Д.) ) ваша асинхронная отправка будет внезапно прервана. Если вы заботитесь об этом, взгляните на Phil Haacks WebBackgrounder для ASP.NET , который позволяет вам ставить в очередь и выполнять фоновую работу (например, отправку электронной почты) таким образом, чтобы убедитесь, что он корректно завершает работу в случае закрытия домена приложения.

27
ответ дан 29 November 2019 в 02:24
поделиться

С помощью .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

1
ответ дан 29 November 2019 в 02:24
поделиться
Другие вопросы по тегам:

Похожие вопросы: