123 votes

Quelles sont les meilleures pratiques pour utiliser SmtpClient, SendAsync et Dispose sous .NET 4.0

Je suis un peu perplexe sur la façon de gérer SmtpClient maintenant qu'il est jetable, surtout si je fais des appels à l'aide de SendAsync. Sans doute que je ne devrais pas appeler dispose jusqu'à SendAsync complète. Mais dois-je l'appeler (par exemple, à l'aide de "l'aide"). Le scénario est un service WCF qui envoie e-mail périodiquement lors des appels. La plupart du calcul est rapide, mais l'envoi d'e-mail peut prendre une seconde ou deux, de manière Asynchrone serait préférable.

Dois-je créer un nouveau SmtpClient à chaque fois de m'envoyer par mail? Dois-je en créer un pour l'ensemble de la WCF? À l'aide!

Mise à jour Dans le cas où il fait une différence, chaque e-mail est toujours adapté à l'utilisateur. La WCF est hébergé sur Azure et Gmail est utilisé comme mailer.

178voto

Boris Lipschitz Points 1434

La question initiale avait été posée pour .NET 4, mais si cela s’avérait utile dès .NET 4.5, SmtpClient implémentait la méthode asynchrone attendue SendMailAsync .

En conséquence, envoyer un courrier électronique de manière asynchrone est le suivant:

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

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

    using (var smtpClient = new SmtpClient())
    {
        await smtpClient.SendMailAsync(message);
    }
}
 

Il est préférable d'éviter d'utiliser la méthode SendAsync.

148voto

TheCodeKing Points 11632

Vous devez toujours disposer des instances IDisposable dans les meilleurs délais. Dans le cas d'appels asynchrones, c'est sur le rappel après l'envoi du message.

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

C'est un peu gênant que SendAsync n'accepte pas de rappel.

16voto

jeroenh Points 12777

En général, IDisposable objets doivent être éliminés dès que possible; la mise en œuvre de IDisposable sur un objet est destiné à communiquer sur le fait que la classe en question détient cher qui devrait être publié de façon déterministe. Cependant, si la création de ces ressources est cher et vous avez besoin de construire un grand nombre de ces objets, il peut être mieux (performance sage) pour conserver une instance dans la mémoire et le réutiliser. Il n'y a qu'une seule façon de savoir si cela fait une différence: profil!

Re: l'élimination et Async: vous ne pouvez pas utiliser using évidemment. Au lieu de vous généralement disposer de l'objet dans le SendCompleted événement:

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

6voto

Anton Skovorodko Points 108

Vous pouvez voir pourquoi il est particulièrement important de disposer de SmtpClient par le commentaire suivant:

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

Dans mon scénario d’envoi de plusieurs courriels à l’aide de Gmail sans disposer du client, j’avais l'habitude d'obtenir:

Message: Service non disponible, fermeture du canal de transmission. La réponse du serveur était la suivante: 4.7.0 Problème système temporaire. Réessayez plus tard (WS). oo3sm17830090pdb.64 - gsmtp

6voto

jmelhus Points 445

Ok, vieille question je sais. Mais je suis tombé sur moi-même quand j'avais besoin de mettre en œuvre quelque chose de similaire. Je voulais juste partager du code.

Je répète sur plusieurs SmtpClients d'envoyer plusieurs mails de manière asynchrone. Ma solution est similaire à TheCodeKing, mais je dispose à la place de l'objet de rappel. Je passe également MailMessage en tant que userToken pour l'obtenir dans l'événement SendCompleted afin que je puisse également appeler dispose à ce sujet. Comme ça:

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X