Concepto simple aquí. Esto es para un sitio que se está construyendo utilizando MVC 3 y Entity Framework 4. Después de que un usuario se registra en el sitio, se envía un correo electrónico a su dirección de correo electrónico. Primero lo implementé usando SmtpClient.Send() y funcionó bien. Luego tuve la brillante idea de intentar enviar el correo electrónico de forma asíncrona. Tengo problemas con los dos enfoques asíncronos que he probado.Dos formas de enviar correo electrónico a través de SmtpClient de forma asíncrona, resultados diferentes
primera implementación (de este post sin respuesta: https://stackoverflow.com/questions/7558582/how-to-dispose-using-smtpclient-send-and-asynccallback):
public bool Emailer(){
.
.
.
using (var smtpClient = new SmtpClient())
{
smtpClient.EnableSsl = true;
smtpClient.Host = "smtp.gmail.com";
smtpClient.Port = 587;
smtpClient.UseDefaultCredentials = false;
smtpClient.Credentials = new NetworkCredential("[email protected]", "mypassword");
var sd = new SendEmailDelegate(smtpClient.Send);
var cb = new AsyncCallback(SendEmailResponse);
sd.BeginInvoke(message, cb, sd);
return true;
}
}
private delegate void SendEmailDelegate(System.Net.Mail.MailMessage m);
private static void SendEmailResponse(IAsyncResult ar)
{
try
{
SendEmailDelegate sd = (SendEmailDelegate)(ar.AsyncState);
sd.EndInvoke(ar); // "cannot access a disposed object" errors here
}
catch (Exception e)
{
_logger.WarnException("Error on EndInvoke.", e);
}
}
Esto funcionaba la mitad del tiempo. La otra mitad recibiría un error "No se puede acceder a un objeto eliminado" en la devolución de llamada.
siguiente aplicación (de un miembro de la reputación sólida: What are best practices for using SmtpClient, SendAsync and Dispose under .NET 4.0):
var smtpClient = new SmtpClient();
smtpClient.EnableSsl = true;
smtpClient.Host = "smtp.gmail.com";
smtpClient.Port = 587;
smtpClient.UseDefaultCredentials = false;
smtpClient.Credentials = new NetworkCredential("[email protected]", "mypassword");
smtpClient.SendCompleted += (s, e) =>
{
smtpClient.Dispose();
message.Dispose();
};
smtpClient.SendAsync(message, null);
Con esta aplicación no consigo ningún error, pero hay un retraso notablemente más largo (~ 5 segundos) en el modo de depuración cuando SMTPClient. SendAsync() se ejecuta, lo que me lleva a pensar que no se envía de forma asincrónica.
Preguntas:
1) lo que está mal en el primer método que está causando los errores "objeto desechado"?
2) ¿La segunda implementación tiene un problema que causa que el correo electrónico no se envíe de forma asíncrona? ¿Es la demora de 5 segundos sin sentido?
También podría ser importante tener en cuenta que aunque el sitio no necesitará admitir el envío de un gran número de correos electrónicos (solo registro de usuarios, boletines opcionales, etc.), anticipamos una gran cantidad de usuarios en el futuro, de ahí mi decisión de enviar correos electrónicos de forma asincrónica.
Gracias.
Gracias por la respuesta. Ahora veo que el objeto está dispuesto antes de que el controlador tenga la oportunidad de disparar. Además, entiendo que tanto SmtpClient se debe eliminar como que se debe invocar a EndInvoke. ¿El acercamiento # 2 logra esto? –