C#如何正确处理SmtpClient?

时间:2010-05-06 12:37:07

标签: c# .net-4.0

VS 2010代码分析报告如下:

警告4 CA2000:Microsoft.Reliability:在方法'Mailer.SendMessage()'中,对象'client'未沿所有异常路径放置。对所有对它的引用超出范围之前,在对象'client'上调用System.IDisposable.Dispose。

我的代码是:

public void SendMessage()
    {
        SmtpClient client = new SmtpClient();

        client.Send(Message);
        client.Dispose(); 
        DisposeAttachments(); 
    }

我应该如何正确处理客户?

更新:回答Jons问题,这是配置附件功能:

private void DisposeAttachments()
{
    foreach (Attachment attachment in Message.Attachments)
    {
        attachment.Dispose();
    }
    Message.Attachments.Dispose();
    Message = null; 
}

上次更新完整课程列表(简称)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Mail;

public class Mailer
    {
    public MailMessage Message
    {
        get;
        set;
    }

    public Mailer(MailMessage message)
    {
        this.Message = message; 
    }

    public void SendMessage()
    {
        using (SmtpClient client = new SmtpClient())
        {
            client.Send(Message);
        }
        DisposeAttachments(); 
    }

    private void DisposeAttachments()
    {
        foreach (Attachment attachment in Message.Attachments)
        {
            attachment.Dispose();
        }
        Message.Attachments.Dispose();
        Message = null; 
    }
    }

7 个答案:

答案 0 :(得分:47)

public void SendMessage()
{
    using (SmtpClient client = new SmtpClient())
    {
        client.Send(Message);
    }
    DisposeAttachments(); 
}

这样,即使在Send方法调用期间抛出异常,客户端也将被处置。您应该很少需要明确地调用Dispose - 它应该几乎总是在using语句中。

但是,目前还不清楚附件是如何涉及的。你的班级本身是否实施IDisposable?如果是这样,那可能是处理附件的地方,这些附件可能是成员变量。如果你需要确保他们在这里处置,你可能需要:

public void SendMessage()
{
    try
    {
        using (SmtpClient client = new SmtpClient())
        {
            client.Send(Message);
        }
    }
    finally
    {
        DisposeAttachments(); 
    }
}

答案 1 :(得分:12)

.NET 4.0中的SmtpClient类现在实现IDisposable,而.NET 2.0中的SmtpClient类缺少此接口(如Darin所说)。这是框架中的重大更改,您应该在迁移到.NET 4.0时采取适当的操作。但是,在迁移到.NET 4.0之前,可以在代码中缓解此问题。这是一个例子:

var client = new SmtpClient();

// Do not remove this using. In .NET 4.0 SmtpClient implements IDisposable.
using (client as IDisposable)
{
    client.Send(message);
} 

此代码将在.NET 2.0(+3.0和3.5)和.NET 4.0下正确编译和运行。

答案 2 :(得分:7)

using (SmtpClient client = new SmtpClient())
{
    client.Send(Message);
    DisposeAttachments(); 
}

有趣 - 与.NET 3.5相反,SmtpClient在.NET 4.0中实现IDisposable,每天都在学习新东西。

答案 3 :(得分:5)

我会做那样的事情:

class Attachments : List<Attachment>, IDisposable
{
  public void Dispose()
  {
    foreach (Attachment a in this)
    {
      a.Dispose();
    }
  }
}

class Mailer : IDisposable
{
  SmtpClient client = new SmtpClient();
  Attachments attachments = new Attachments();

  public SendMessage()
  {
    [... do mail stuff ...]
  }

  public void Dispose()
  {
    this.client.Dispose();
    this.attachments.Dispose();
  }
}


[... somewhere else ...]
using (Mailer mailer = new Mailer())
{
  mailer.SendMail();
}

如果你想发送多封邮件,这将允许重复使用SmtpClient对象。

答案 4 :(得分:2)

这是通过代码警察测试的更整洁的解决方案(如果发送失败,将始终调用dispose):

public void SendMessage()
{
    using (SmtpClient client = new SmtpClient())
    {   
        client.Send(Message);
        DisposeAttachments(); 
    }
}

答案 5 :(得分:0)

我最初的问题是关于间歇性发送失败。 例如。第一个 Send() 成功,第二个 Send() 失败,第三个 Send() 成功。 起初我以为我没有正确处理。 所以我求助于using()

无论如何,后来我添加了 UseDefaultCredentials = false,Send() 终于稳定了。我仍然保留了 using() 函数。

答案 6 :(得分:-4)

public void SendMessage()
{
    try
    {
        using (SmtpClient client = new SmtpClient())
        {
            client.Send(Message);
        client.dispose()

        }
    }
    finally
    {
        DisposeAttachments(); 
    }
}