Каковы наилучшие методы использования SmtpClient, SendAsync и Dispose в .NET 4.0

Я немного озадачен тем, как управлять SmtpClient сейчас, когда он доступен, особенно если я делаю вызовы с помощью SendAsync. Предположительно, я не должен вызывать Dispose до тех пор, пока не будет выполнен SendAsync. Но должен ли я когда-либо называть это (например, используя "использование" ). Сценарий - это служба WCF, которая периодически высылает сообщения по электронной почте при выполнении вызовов. Большая часть вычислений выполняется быстро, но отправка электронной почты может занимать секунду или около того, поэтому Async будет предпочтительнее.

Должен ли я создавать новый SmtpClient каждый раз при отправке почты? Должен ли я создать его для всего WCF? Помогите!

Обновить. Если это имеет значение, каждое электронное письмо всегда настраивается для пользователя. WCF размещен на Azure, а Gmail используется как почтовая программа.

Ответ 1

Примечание..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);

Немного раздражает SendAsync не принимает обратный вызов.

Ответ 2

Первоначальный вопрос был задан для .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);
        }
    }
}

Лучше избегать использования метода SendAsync.

Ответ 3

В общем, IDisposable объекты должны быть удалены как можно скорее; реализация IDisposable на объекте предназначена для передачи информации о том, что рассматриваемый класс содержит дорогостоящие ресурсы, которые следует детерминировать. Однако, если создание этих ресурсов является дорогостоящим, и вам нужно построить много таких объектов, может быть лучше (с точки зрения производительности) сохранить один экземпляр в памяти и повторно использовать его. Есть только один способ узнать, имеет ли это значение: профилируйте его!

Re: disposing и Async: вы не можете использовать using, очевидно. Вместо этого вы обычно располагаете объект в событии SendCompleted:

var smtpClient = new SmtpClient();
smtpClient.SendCompleted += (s, e) => smtpClient.Dispose();
smtpClient.SendAsync(...);

Ответ 4

Хорошо, старый вопрос, который я знаю. Но я сам наткнулся на это, когда мне нужно было что-то подобное. Я просто хотел поделиться некоторым кодом.

Я повторяю несколько SmtpClients, чтобы отправить несколько писем асинхронно. Мое решение похоже на TheCodeKing, но вместо этого я удаляю объект обратного вызова. Я также передаю MailMessage как userToken, чтобы получить его в событии SendCompleted, чтобы я мог также вызывать его. Вот так:

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);
}

Ответ 5

Вы можете понять, почему особенно важно избавиться от 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();

В моем сценарии, отправляющем несколько писем с использованием Gmail без утилизации клиента, я использовал:

Сообщение: услуга недоступна, закрывается канал передачи. Ответ сервера: 4.7.0 Временная системная проблема. Попробуйте позже (WS). oo3sm17830090pdb.64 - gsmtp