我正在尝试学习和掌握 ASYNC 和 AWAIT,但不清楚我所做的是否正确。我的意思是代码有效,我使用了两个相同形式的浏览器/实例并单击,好吧,几乎在同一时间,一切顺利。我收到了 2 封电子邮件,但这样做是否正确?异步而不是同步是否真的提供了额外的值(value)...
这是我的代码:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel model)
{
bla bla do some sync simple stuffs etc...
...
await Task.Run(() => Utility.MailUtility.SendEmail(user.Email, user.To, msg, subj));
return RedirectToAction("Index", "Home");
}
根据取自 stackoverflow 的示例代码,邮件代码如下所示:
public static async Task SendEmail(params etc...)
{
await SendMailForTemplateID(params etc...);
}
private static Task SendMailForTemplateID(params etc...)
{
var task = Task.Factory.StartNew(() =>
{
MailMessage message = new MailMessage();
MailMessage mail = new MailMessage();
//SmtpClient SmtpServer = new SmtpClient(ConfigurationManager.AppSettings["SMTPHost"]);
SmtpClient SmtpServer = new SmtpClient("localhost"); // for test purpose only
mail.From = new MailAddress(from);
mail.To.Add(to);
mail.Subject = GetSubjectForTemplateId(templateID, extraMsg, dataInfo, fromName, toName, isFr);
mail.Body = GetBodyForTemplateId(templateID, extraMsg, dataInfo, fromName, toName, isFr);
mail.IsBodyHtml = false;
SmtpServer.Port = 81; // for test purpose only
SmtpServer.Credentials = new System.Net.NetworkCredential
(ConfigurationManager.AppSettings["CredentialUser"],
ConfigurationManager.AppSettings["CredentialPassword"]);
bool result;
bool.TryParse(ConfigurationManager.AppSettings["EnableSSL"], out result);
SmtpServer.EnableSsl = result;
SmtpServer.Send(mail);
//* make sure we leave nothing in memory
message.Dispose();
mail.Dispose();
SmtpServer.Dispose();
});
return task;
}
很抱歉,我不知道如何在我的回复之间添加回车(回车)。是否可以? nway,关于 ASYNC-EMAIL 最佳实践。
我的新版本代码看起来像这样,它的编码更简单,但对吗?我的意思是没有新线程,它是否提供了额外的值(value) VS 同步 sendmail 方法等...
我在 MVC 操作中调用它。代码:
do stuff...
await Utility.MailUtility.SendMailForTemplateID(params);
do stuff...
public static async Task SendMailForTemplateID(params...)
{
try
{
email code etc...
await smtpClient.SendMailAsync(mail);
mail.Dispose();
smtpClient.Dispose();
}
catch (Exception)
{
// Log ex
}
}
请您参考如下方法:
不,将异步调用包装到 Task.Run 中是编写 async/await 代码的错误方式。
当前代码的一个特殊问题是 Task.Run 和 Task.Factory.StartNew 启动新线程来执行操作 - 因此代码启动 2 个额外线程来执行操作.
正确的方法 - 删除所有 Task.Run/Task.Factory.StartNew 调用和 await 异步调用。在你的情况下 SmtpClient.SendMailAsync应该在最低级别使用而不是 SmtpServer.Send(mail);。
在更通用的情况下,当没有基于任务的 API 但有一些替代的异步 API(如基于事件的 SmtpClient.SendAsync )时,您可能需要提供包装辅助方法以将此类调用转换为基于任务的 异步 方法。 Convert Event based pattern to async CTP pattern 中显示的一些方法
大概代码:
public async Task<ActionResult> Register(RegisterViewModel model)
{
...
await Utility.MailUtility.SendEmailAsync(user.Email, user.To, msg, subj));
return RedirectToAction("Index", "Home");
}
// No need to add `async` here as there is no `await` inside,
// possibly can be removed altogether.
public static Task SendEmailAsync(params etc...)
{
return SendMailForTemplateID(params etc...);
}
private async static Task SendMailForTemplateID(params etc...)
{
// not Task.Run / Task.Factory.StartNew
using (MailMessage message = ... )
using (SmtpClient smtp = ....)
{
.... // setup message/smtp
await smtp.SendMailAsync(mail); // Task-based Send
}
// no need to return anything for `Task` (essentially `void`) method
}
