2010-05-06 11 views
26

VS 2010 de análisis de código informa de lo siguiente:C# cómo desechar correctamente un SmtpClient?

Advertencia 4 CA2000: Microsoft.Reliability: En el método de 'Mailer.SendMessage()', objeto 'cliente' no está dispuesto a lo largo de todos los caminos de excepción. Call System.IDisposable.Dispose en el objeto 'client' antes de que todas las referencias estén fuera del alcance.

Mi código es:

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

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

¿Cómo debo desechar correctamente cliente?

Actualización: a responder a la pregunta Jons, aquí está el adjuntos funcionalidad disponer:

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

Última actualización lista de clases completo (su corta)

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; 
    } 
    } 
+6

@JL - en lugar de deshacerse de los archivos adjuntos manualmente, debe deshacerse del mensaje de correo que dispone de archivos adjuntos, vistas alternativas y otras piezas. – Giorgi

+1

Verdadero pero en versión heredada (pre .net 4.0) SmtpClient no implementó un método de eliminación –

Respuesta

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

De esta forma el cliente estará dispuesto incluso si se produce una excepción durante la llamada Send método. Rara vez debe llamar al Dispose explícitamente, casi siempre debe estar en una declaración using.

Sin embargo, no está claro cómo los anexos están involucrados aquí. ¿Su clase implementa IDisposable? Si es así, ese es probablemente el lugar para deshacerse de los archivos adjuntos que son, presumiblemente, variables miembro. Si tiene que estar absolutamente seguro de que quedan dispuestas aquí, es probable que tenga:

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

@Jon pregunta actualizada ... –

+0

@JL: Hmm ... todavía parece que los archivos adjuntos deberían eliminarse como parte de la * instancia * que se va a eliminar, probablemente. Su mensaje 'DisposeAttachments' también significa que no puede ver el mensaje después, lo que suena un poco extraño ... –

+0

una vez que se envía el mensaje, no necesito una instancia para enviar mensajes o archivos adjuntos. ¿Debo implementar un destructor? –

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

Interesante - contrario a .NET 3.5, SmtpClient implementa IDisposable en .NET 4 .0, aprendiendo cosas nuevas todos los días.

+0

El principal beneficio de @Darin es que el cliente SMTP ahora envía el comando QUIT finalmente durante un desecho :) ¡muy contento con esto! –

+0

@Darin: ¿WTF? SmtpClient implementa IDisposable en .NET 4.0 ??? Este es un gran cambio radical. Esto duele. – Steven

+0

@Steven, sí, y parece que finalmente cierra la conexión de manera correcta enviando el comando QUIT al servidor. –

2

Esta es (siempre será llamado y disponer si Enviar falla) la solución más ordenado que pasar la prueba de la policía código:

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

que haría algo así:

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

Esto permitiría reutilizar el objeto SmtpClient si desea enviar varios mensajes.

+0

¡Ese código es muy lindo, muchas gracias! –

11

La clase SmtpClient en .NET 4.0 ahora implementa IDisposable, mientras que la clase SmtpClient en .NET 2.0 carece de esta interfaz (como señaló Darin). Este es un cambio radical en el marco y debe tomar las medidas adecuadas al migrar a .NET 4.0. Sin embargo, es posible mitigar esto en su código antes de migrar a .NET 4.0. Aquí es un ejemplo de tales:

var client = new SmtpClient(); 

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

Este código compilar y ejecutar correctamente tanto bajo .NET 2.0 (3.0 y 3.5) y bajo .NET 4.0.

+1

Pero ... ¿será útil deshacerse del cliente correctamente? – Nyerguds

+0

Porque el problema real con la versión 3.5 anterior es que no envía un mensaje QUIT al servidor, lo que hace que el servidor siga esperando las comunicaciones. Esto aparentemente causa problemas cuando se vuelve a conectar al mismo servidor. – Nyerguds

+0

@Nyerguds: Esta construcción no solucionará eso, por supuesto. – Steven

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

     } 
    } 
    finally 
    { 
     DisposeAttachments(); 
    } 
} 
+1

Por favor, intente proporcionar su código solo responda con alguna descripción –

+5

Llamar a 'Dispose()' dentro de un bloque 'using' parece completamente redundante. – Nyerguds

Cuestiones relacionadas