.SendMailAsync()中使用MVC [英] .SendMailAsync() use in MVC

查看:104
本文介绍了.SendMailAsync()中使用MVC的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想从我的MVC应用程序发送电子邮件,发送精细当我使用。发送()方法,但需要一段时间才能回来,所以我想用.SendMailAsync()函数,但我收到在执行过程中下面的错误。


  

这是异步操作不能在这个时间开始。异步操作只能在异步处理程序或模块内或在在页面生命周期的某些事件开始。如果在执行一个页面出现了这种异常,保证页面被标记为LT;%@页面异步=真正的%>


这是我的code样品。如何配置这一点使用.SendMailAsync发送()

电子邮件包装类:

 使用System.Net.Mail;命名空间助手
{
    公共类电子邮件
    {
        //常量
        私人常量字符串HtmlEmailHeader =< HTML>< HEAD><标题>< /标题>< /头><车身风格=FONT-FAMILY:宋体; FONT-SIZE:14px的;>中;
        私人常量字符串HtmlEmailFooter =< /身体GT;< / HTML>中;        //性质
        公开名单<串GT;要得到;组; }
        公开名单<串GT; CC {搞定;组; }
        公开名单<串GT; BCC {搞定;组; }
        公共字符串从{搞定;组; }
        公共字符串主题{搞定;组; }
        公共字符串车身{搞定;组; }        //构造
        公共电子邮件()
        {
            为了=新的List<串GT;();
            CC =新的List<串GT;();
            BCC =新的List<串GT;();
        }        //发送
        公共无效的send()
        {
            消息MAILMESSAGE新= MAILMESSAGE();            的foreach(在为VAR X)
            {
                message.To.Add(X);
            }
            的foreach(在CC变种X)
            {
                message.CC.Add(X);
            }
            的foreach(BCC中VAR X)
            {
                message.Bcc.Add(X);
            }            message.Subject =主题;
            message.Body = string.Concat(HtmlEmailHeader,身体,HtmlEmailFooter);
            message.BodyEncoding = System.Text.Encoding.UTF8;
            message.From =新的MailAddress(从);
            message.SubjectEncoding = System.Text.Encoding.UTF8;
            message.IsBodyHtml = TRUE;            SmtpClient客户端=新SmtpClient(relay.mail.server);            client.SendMailAsync(消息);
        }
    }
}

控制器:

 公众的ActionResult指数()
    {        电子邮件电子邮件=新的电子邮件();
        email.To.Add(to@email.com);
        email.From =from@email.com;
        email.Subject =主题;
        email.Body =< P><强>你好< / STRONG>< / P>< P>这是我的第一个电邮讯息和LT; / P>中;
        email.Send();
    }

修改

为进一步询问实际问题,根本问题是发送电子邮件时所创建的延迟。我进一步调查了实际的问题,这个职位的帮助:

<一个href=\"http://stackoverflow.com/questions/3637649/asp-net-mvc-background-threads-for-email-creation-and-sending\">ASP.Net MVC后台线程的电子邮件创建和发送

修改我的电子邮件包装类产卵了一个新的线程来执行的电子邮件处理:

 使用System.Net.Mail;命名空间助手
{
    公共类电子邮件
    {
        //常量
        私人常量字符串HtmlEmailHeader =&LT; HTML&GT;&LT; HEAD&GT;&LT;标题&GT;&LT; /标题&GT;&LT; /头&GT;&LT;车身风格=FONT-FAMILY:宋体; FONT-SIZE:14px的;&gt;中;
        私人常量字符串HtmlEmailFooter =&LT; /身体GT;&LT; / HTML&gt;中;        //性质
        公开名单&LT;串GT;要得到;组; }
        公开名单&LT;串GT; CC {搞定;组; }
        公开名单&LT;串GT; BCC {搞定;组; }
        公共字符串从{搞定;组; }
        公共字符串主题{搞定;组; }
        公共字符串车身{搞定;组; }        //构造
        公共电子邮件()
        {
            为了=新的List&LT;串GT;();
            CC =新的List&LT;串GT;();
            BCC =新的List&LT;串GT;();
        }        //发送
        公共无效的send()
        {
            消息MAILMESSAGE新= MAILMESSAGE();            的foreach(在为VAR X)
            {
                message.To.Add(X);
            }
            的foreach(在CC变种X)
            {
                message.CC.Add(X);
            }
            的foreach(BCC中VAR X)
            {
                message.Bcc.Add(X);
            }            message.Subject =主题;
            message.Body = string.Concat(HtmlEmailHeader,身体,HtmlEmailFooter);
            message.BodyEncoding = System.Text.Encoding.UTF8;
            message.From =新的MailAddress(从);
            message.SubjectEncoding = System.Text.Encoding.UTF8;
            message.IsBodyHtml = TRUE;            SmtpClient客户端=新SmtpClient(relay.mail.server);            新的Thread(()=&GT; {client.Send(消息);})。开始();
        }
    }
}


解决方案

诚然,错误是有点钝,但所有它的真正告诉你的是,你调用从同步方法,这是不是一种异步方法允许的。如果你要使用异步,你必须异步一路上扬链使用。

所以,首先你需要改变你的发送方法定义返回工作

 公共异步任务发送()

和设置您的异步方法调用,以等待:

 等待client.SendMailAsync(消息);

然后,你的行动做相同的:

 公共异步任务&LT;&的ActionResult GT;指数()

 等待email.Send();

更新

异步并没有做什么,我想你想它。当你的行动是由一个请求调用时,它不会返回,直到的所有的$ C $的动作里面C已经完全执行的响应。异步是没有魔杖,使行动回报的响应速度更快。的任务(在此情况下,发送电子邮件)开,只要其需要和异步与否,直到任务已经完成了动作不会返回响应。

那么,为什么异步然后用?因为什么异步的确实的要做的就是放开线程从服务器池。比方说,IIS是在pretty标准配置运行,你可能有可用的某处大约1000年线程。这通常被称为最大的要求,因为通常1请求== 1线程。所以,如果你的服务器来重负载下,你就派出比最大的要求多,每个后续请求排队,直到从池中的线程将再次变得可用。如果所有线程都绑起来等待的东西来完成,那么你的服务器基本上是死锁。但是,当你使用异​​步,你告诉IIS本质,我在等待的东西。这里是我的线程回来,所以你可以用它来现场另一个请求。我要让你知道,当我需要它了。允许在队列中的请求继续进行。

长与短,不要总是使用,当你做任何事情,包括等待异步的,因为它可以让服务器资源得到更有效的利用,但请记住,它不会让事情发生快。

修改14年12月11日 - 更新术语有点清楚,当一个线程的的,不只是参与了一些长时间运行的异步是唯一有用任务。例如,在运行复杂的财务计算可能需要一段时间,但因为所有的工作是CPU密集型的将不会是一个很好的适合异步。该任务可能是长期运行的,但如果线程不处于等待状态,不能用于其他任务,你的异步方法本质上只是作为运行同步,但有额外的开销。

I am trying to send email from my MVC application, it sends fine when I use the .Send() method but takes a while to come back so I wanted to use the .SendMailAsync() function, but I am receiving the following error during execution.

An asynchronous operation cannot be started at this time. Asynchronous operations may only be started within an asynchronous handler or module or during certain events in the Page lifecycle. If this exception occurred while executing a Page, ensure that the Page is marked <%@ Page Async="true" %>

This is my code sample. How can I configure this to send using .SendMailAsync()

Email Wrapper Class:

using System.Net.Mail;

namespace Helpers
{
    public class Email
    {
        // constants
        private const string HtmlEmailHeader = "<html><head><title></title></head><body style='font-family:arial; font-size:14px;'>";
        private const string HtmlEmailFooter = "</body></html>";

        // properties
        public List<string> To { get; set; }
        public List<string> CC { get; set; }
        public List<string> BCC { get; set; }
        public string From { get; set; }
        public string Subject { get; set; }
        public string Body { get; set; }  

        // constructor
        public Email()
        {
            To = new List<string>();
            CC = new List<string>();
            BCC = new List<string>();
        }

        // send
        public void Send()
        {
            MailMessage message = new MailMessage();

            foreach (var x in To)
            {
                message.To.Add(x);
            }
            foreach (var x in CC)
            {
                message.CC.Add(x);
            }
            foreach (var x in BCC)
            {
                message.Bcc.Add(x);
            }

            message.Subject = Subject;
            message.Body = string.Concat(HtmlEmailHeader, Body, HtmlEmailFooter);
            message.BodyEncoding = System.Text.Encoding.UTF8;
            message.From = new MailAddress(From);
            message.SubjectEncoding = System.Text.Encoding.UTF8;
            message.IsBodyHtml = true;

            SmtpClient client = new SmtpClient("relay.mail.server");

            client.SendMailAsync(message);            
        }
    }
}

Controller:

public ActionResult Index()
    {

        Email email = new Email();
        email.To.Add("to@email.com");
        email.From = "from@email.com";
        email.Subject = "Subject";
        email.Body = "<p><strong>Hello</strong></p><p>This is my first Email Message</p>";
        email.Send();
    }

EDIT

Further to the actual question asked, the underlying issue was the delay created when sending emails. I looked further into the actual issue and with the help of this post:

ASP.Net MVC background threads for email creation and sending

modified my Email Wrapper class to spawn off a new thread to perform the email processing:

using System.Net.Mail;

namespace Helpers
{
    public class Email
    {
        // constants
        private const string HtmlEmailHeader = "<html><head><title></title></head><body style='font-family:arial; font-size:14px;'>";
        private const string HtmlEmailFooter = "</body></html>";

        // properties
        public List<string> To { get; set; }
        public List<string> CC { get; set; }
        public List<string> BCC { get; set; }
        public string From { get; set; }
        public string Subject { get; set; }
        public string Body { get; set; }  

        // constructor
        public Email()
        {
            To = new List<string>();
            CC = new List<string>();
            BCC = new List<string>();
        }

        // send
        public void Send()
        {
            MailMessage message = new MailMessage();

            foreach (var x in To)
            {
                message.To.Add(x);
            }
            foreach (var x in CC)
            {
                message.CC.Add(x);
            }
            foreach (var x in BCC)
            {
                message.Bcc.Add(x);
            }

            message.Subject = Subject;
            message.Body = string.Concat(HtmlEmailHeader, Body, HtmlEmailFooter);
            message.BodyEncoding = System.Text.Encoding.UTF8;
            message.From = new MailAddress(From);
            message.SubjectEncoding = System.Text.Encoding.UTF8;
            message.IsBodyHtml = true;

            SmtpClient client = new SmtpClient("relay.mail.server");

            new Thread(() => { client.Send(message); }).Start();        
        }
    }
}

解决方案

Admittedly, the error is a bit obtuse, but all it's really telling you is that you're calling an asynchronous method from a synchronous method, which isn't allowed. If you're going to use async, you have to use async all the way up the chain.

So, first you need to change your Send method definition to return a Task:

public async Task Send()

And set your async method call to await:

await client.SendMailAsync(message);

Then, do the same for your action:

public async Task<ActionResult> Index()

And:

await email.Send();

UPDATE

Async doesn't do what I think you think it does. When your action is invoked by a request, it will not return a response until all code inside the action has fully executed. Async is not a magic wand that makes the action return the response quicker. Your task (in this case, sending an email) takes as long as it takes and async or not, the action will not return a response until the task has completed.

So why use async then? Because what async does do is let go the thread from the server pool. Let's say IIS is running in a pretty standard config, you'll likely have somewhere around 1000 threads available. This is often called the "max requests", because typically 1 request == 1 thread. So, if you server comes under heavy load and you're fielding more than the "max requests", each subsequent request is queued until a thread from the pool becomes available again. If all the threads are tied up waiting on something to complete, then your server essentially deadlocks. But, when you use async, you tell IIS essentially, "I'm waiting on something. Here's my thread back, so you can use it to field another request. I'll let you know when I need it back." That allows requests in the queue to proceed.

Long and short, do always use async when you are doing anything that involves waiting, because it allows server resources to be used more efficiently, but remember that it doesn't make things happen quicker.

EDIT 12/11/14 - Updated terminology a bit to make clear that async is only useful when a thread is waiting, not just involved in some long-running task. For example, running complex financial calculations could "take a while", but would not be a good fit for async because all the work is CPU-bound. The task may be long-running, but if the thread is not in a wait-state, it can't be used for other tasks and your async method will essentially just run as sync, but with extra overhead.

这篇关于.SendMailAsync()中使用MVC的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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