SmtpClient.SendAsync阻止我的ASP.NET MVC请求 [英] SmtpClient.SendAsync blocking my ASP.NET MVC Request

查看:223
本文介绍了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)
{
元组< 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 ,它让您排队并运行后台工作(如发送电子邮件),以确保它在应用程序域关闭的情况下,可以优雅地完成。


I have a Action that sends a simple email:

    [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);
    }

And a email service:

    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)
        {

        }
    }

When I send a email, I am using Async method, then my method SendAsync return immediately, then RedirectToAction is called. But the response(in this case a redirect) isn´t sent by ASP.NET until client_SendCompleted is completed.

Here's what I'm trying to understand:

When watching the execution in Visual Studio debugger, the SendAsync returns immediately (and RedirectToAction is called), but nothing happens in the browser until email is sent?

If i put a breakpoint inside client_SendCompleted, the client stay at loading.... until I hit F5 at debugger.

解决方案

This is by design. ASP.NET will automatically wait for any outstanding async work to finish before finishing the request if the async work was kicked off in a way that calls into the underlying SynchronizationContext. This is to ensure that if your async operation tries to interact with the HttpContext, HttpResponse, etc. it will still be around.

If you want to do true fire & forget, you need to wrap your call in ThreadPool.QueueUserWorkItem. This will force it to run on a new thread pool thread without going through the SynchronizationContext, so the request will then happily return.

Note however, that if for any reason the app domain were to go down while your send was still in progress (e.g. if you changed the web.config file, dropped a new file into bin, the app pool recycled, etc.) your async send would be abruptly interrupted. If you care about that, take a look at Phil Haacks WebBackgrounder for ASP.NET, which let's you queue and run background work (like sending an email) in such a way that will ensure it gracefully finishes in the case the app domain shuts down.

这篇关于SmtpClient.SendAsync阻止我的ASP.NET MVC请求的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆