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

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

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

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

101 голос | спросил tofutim 2 ndEurope/Moscowp30Europe/Moscow09bEurope/MoscowFri, 02 Sep 2011 00:51:08 +0400 2011, 00:51:08

5 ответов


0

Примечание: .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 не принимает обратный вызов.

ответил TheCodeKing 2 ndEurope/Moscowp30Europe/Moscow09bEurope/MoscowFri, 02 Sep 2011 01:32:41 +0400 2011, 01:32:41
0

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

ответил Boris Lipschitz 18 MaramTue, 18 Mar 2014 10:06:51 +04002014-03-18T10:06:51+04:0010 2014, 10:06:51
0

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

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

var smtpClient = new SmtpClient();
smtpClient.SendCompleted += (s, e) => smtpClient.Dispose();
smtpClient.SendAsync(...);
ответил jeroenh 2 ndEurope/Moscowp30Europe/Moscow09bEurope/MoscowFri, 02 Sep 2011 01:29:43 +0400 2011, 01:29:43
0

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

Я перебираю несколько 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);
}
ответил jmelhus 18 J000000Friday14 2014, 01:39:15
0

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

ответил Anton Skovorodko 20 AM000000110000001631 2014, 11:04:16

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132