在.NET 4.0下使用SmtpClient,SendAsync和Dispose的最佳实践是什么

tof*_*tim 109 c# .net-4.0 smtpclient

我对如何管理SmtpClient感到有点困惑,因为它是一次性的,特别是如果我使用SendAsync进行调用.据推测,在SendAsync完成之前,我不应该调用Dispose.但我应该打电话给它(例如,使用"使用").该方案是一个WCF服务,它在发出呼叫时定期发送电子邮件.大多数计算速度很快,但发送电子邮件可能需要一秒左右的时间,所以Async会更好.

我每次发邮件时都应该创建一个新的SmtpClient吗?我应该为整个WCF创建一个吗?救命!

更新如果它有所不同,则始终为用户自定义每封电子邮件.WCF托管在Azure上,Gmail用作邮件程序.

Bor*_*itz 159

最初的问题是针对.NET 4提出的,但如果它有助于.NET 4.5 SmtpClient实现异步等待方法 SendMailAsync.

因此,异步发送电子邮件如下:

public async Task SendEmail(string toEmailAddress, string emailSubject, string emailMessage)
{
    using (var message = new MailMessage())
    {
        message.To.Add(toEmailAddress);

        message.Subject = emailSubject;
        message.Body = emailMessage;

        using (var smtpClient = new SmtpClient())
        {
            await smtpClient.SendMailAsync(message);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

最好避免使用SendAsync方法.

  • SendMailAsync()无论如何都是SendAsync()方法的包装器.async/await更整洁,更优雅.它将达到完全相同的要求. (14认同)
  • `MailMessage`也应该是Disposed. (6认同)
  • 你可以随时使用@RodHartzell .ContinueWith() (2认同)
  • 使用 using - 或 dispose - 还是没有实际区别更好?在最后一个“使用”块中,是否有可能在 SendMailAsync 执行之前处理 smtpClient ? (2认同)

The*_*ing 130

注意:.NET 4.5 SmtpClient实现async awaitable方法SendMailAsync.对于较低版本,请SendAsync按照以下说明使用.


你应该尽可能地处理IDisposable实例.在异步调用的情况下,这是在发送消息后的回调.

var message = new MailMessage("from", "to", "subject", "body"))
var client = new SmtpClient("host");
client.SendCompleted += (s, e) => {
                           client.Dispose();
                           message.Dispose();
                        };
client.SendAsync(message, null);
Run Code Online (Sandbox Code Playgroud)

SendAsync不接受回调有点烦人.

  • 在"await"可用之前,没有编写此代码.这是使用事件处理程序的传统回调.如果使用较新的`SendMailAsync`,应该使用`await`. (18认同)
  • 最后一行不应该有'await'吗? (2认同)
  • SmtpException:发送邮件失败.--> System.InvalidOperationException:此时无法启动异步操作.异步操作只能在异步处理程序或模块中启动,或者在页面生命周期中的某些事件中启动.如果在执行页面时发生此异常,请确保将页面标记为<%@ Page Async ="true"%>.此异常还可能表示尝试调用"异步void"方法,该方法通常在ASP.NET请求处理中不受支持.相反,异步方法应该返回一个Task,调用者应该等待它. (2认同)
  • 提供“null”作为“SendAsync(...)”的第二个参数是否安全? (2认同)

jer*_*enh 16

一般而言,IDisisposable对象应尽快处置; 在对象上实现IDisposable旨在传达这样一个事实,即所讨论的类拥有应该确定性释放的昂贵资源.但是,如果创建这些资源很昂贵并且您需要构建大量这些对象,那么将一个实例保留在内存中并重用它可能会更好(性能明智).只有一种方法可以知道这是否有所不同:简介!

Re:处理和异步:你using显然无法使用.相反,您通常将对象放在SendCompleted事件中:

var smtpClient = new SmtpClient();
smtpClient.SendCompleted += (s, e) => smtpClient.Dispose();
smtpClient.SendAsync(...);
Run Code Online (Sandbox Code Playgroud)


jme*_*hus 6

好的,老问题我知道.但是当我需要实现类似的东西时,我偶然发现了这一点.我只是想分享一些代码.

我正在迭代几个SmtpClients以异步发送几个邮件.我的解决方案类似于TheCodeKing,但我正在处理回调对象.我也将MailMessage作为userToken传递给SendCompleted事件,所以我也可以调用dispose.像这样:

foreach (Customer customer in Customers)
{
    SmtpClient smtpClient = new SmtpClient(); //SmtpClient configuration out of this scope
    MailMessage message = new MailMessage(); //MailMessage configuration out of this scope

    smtpClient.SendCompleted += (s, e) =>
    {
        SmtpClient callbackClient = s as SmtpClient;
        MailMessage callbackMailMessage = e.UserState as MailMessage;
        callbackClient.Dispose();
        callbackMailMessage.Dispose();
    };

    smtpClient.SendAsync(message, message);
}
Run Code Online (Sandbox Code Playgroud)

  • 最好的做法是为要发送的每封电子邮件创建一个新的SmtpClient? (2认同)

Ant*_*dko 6

您可以通过以下注释了解为什么处理SmtpClient特别重要:

public class SmtpClient : IDisposable
   // Summary:
    //     Sends a QUIT message to the SMTP server, gracefully ends the TCP connection,
    //     and releases all resources used by the current instance of the System.Net.Mail.SmtpClient
    //     class.
    public void Dispose();
Run Code Online (Sandbox Code Playgroud)

在我的场景中使用Gmail发送多封邮件而不处理客户端,我曾经得到:

消息:服务不可用,关闭传输通道.服务器响应是:4.7.0临时系统问题.稍后再试(WS).oo3sm17830090pdb.64 - gsmtp