Skip to main content
 首页 » 编程设计

c#之这真的是异步电子邮件和最佳实践吗

2024年02月05日29JeffreyZhao

我正在尝试学习和掌握 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  
   }