2009-12-29 14 views
5

Soy relativamente nuevo en C# y .NET y estoy tratando de aprender cómo manejar mejor las excepciones en mi código.¿Cómo debo manejar las excepciones en esta función C#?

Tome la siguiente función que he escrito, por ejemplo:

public void SendEmail(string SenderEmail, string SenderDisplayName, IEnumerable<string> RecipientEmails, string Subject, string Message) 
    { 
     MailMessage message = new MailMessage(); 

     message.From = new MailAddress(SenderEmail, SenderDisplayName); 
     foreach (var recipient in RecipientEmails) 
     { 
      message.To.Add(recipient); 
     } 
     message.Subject = Subject; 
     message.Body = Message; 

     SmtpClient smtpClient = new SmtpClient("192.168.168.182"); 
     smtpClient.Send(message); 
    } 
} 

Si intenta agregar una dirección de correo electrónico que tiene un formato incorrecto en Message.From o Message.To, se lanzará una excepción. En este momento, mi aplicación se está bloqueando y quemando cuando esto sucede.

¿Puede alguien mostrarme la forma adecuada de manejar esa excepción en este método?

Respuesta

18

Esto es ¡la manera apropiada de manejar excepciones!

En general, no se debe manejar una excepción a menos que se pueda corregir el problema, y ​​solo se debe manejar en un lugar donde se pueda aplicar la corrección.

Por ejemplo, la persona que llama de su código puede querer solicitarle al usuario que corrija la dirección de correo electrónico incorrecta. Pero su código no puede saber la forma correcta de solicitarlo. ¿Te llaman desde WinForms o formularios web? ¿Cómo debería ser el cuadro de diálogo? ¿Debería haber en un cuadro de diálogo? Estas son cosas que solo puede conocer la persona que llama de su método y no su propio método.


En la persona que llama:

try 
{ 
    SendEmail(SenderEmail, SenderDisplayName, RecipientEmails, Subject, Message); 
} 
catch (MyMailAddressException ex) 
{ 
    MessageBox.Show(ex.Message); 
} 

Tenga en cuenta que más excepciones que se propagarán a MyMailAddressException código que sabe cómo manejarlos.


Nivel adecuado de "manipulación" en su método:

public enum MailAddressType 
{ 
    Sender, 
    Recipient 
} 

public class MyMailAddressException : Exception 
{ 
    public MailAddressType AddressType { get; set; } 
    public string EmailAddress { get; set; } 

    public MyMailAddressException(
     string message, 
     MailAddressType addressType, 
     string emailAddress, 
     Exception innerException) : base(message, innerException) 
    { 
     AddressType = addressType; 
     EmailAddress = emailAddress; 
    } 
} 

public void SendEmail(
    string senderEmail, 
    string senderDisplayName, 
    IEnumerable<string> recipientEmails, 
    string subject, 
    string message) 
{ 
    using (
     var mailMessage = new MailMessage 
          { 
           Subject = subject, 
           Body = message 
          }) 
    { 
     try 
     { 
      mailMessage.From = new MailAddress(
       senderEmail, senderDisplayName); 
     } 
     catch (FormatException ex) 
     { 
      throw new MyMailAddressException(
       "Invalid from address", MailAddressType.Sender, 
       senderEmail, ex); 
     } 

     foreach (var recipient in recipientEmails) 
     { 
      try 
      { 
       mailMessage.To.Add(recipient); 
      } 
      catch (FormatException ex) 
      { 
       throw new MyMailAddressException(
        "Invalid to address", MailAddressType.Recipient, 
        recipient, ex); 
      } 
     } 

     var smtpClient = new SmtpClient("192.168.168.182"); 
     smtpClient.Send(mailMessage); 
    } 
} 

La persona que llama puede entonces coger MyMailAddressException y tener toda la información necesaria para indicar al usuario qué se debe corregir. Otras excepciones deberían propagarse.


Mis ediciones anteriores han respondido a su pregunta sobre el método. He estado asumiendo que su aplicación tiene un manejo de excepciones de nivel superior apropiado. Gabriel me señala que si tuvieras el manejo de excepciones de nivel superior apropiado, ¡entonces tu aplicación no fallaría!

Sin embargo, colisionar no es necesariamente algo malo. Si ocurre algo que su código no puede manejar, entonces es correcto hacer un bloqueo. La alternativa es tratar de seguir funcionando, con la esperanza de que esta excepción no controlada no haya dañado su programa de tal manera que empiece a producir resultados incorrectos.

Los detalles de dónde colocar exactamente los "controladores de nivel superior" dependen de su programa. Por ejemplo, es diferente entre WinForms y aplicaciones ASP.NET. Sin embargo, el concepto será el mismo: registrar de forma segura toda la información disponible, luego permitir que la excepción se propague y bloquee la aplicación.

Por supuesto, debe utilizar los bloques finally para limpiar su aplicación, incluso en presencia de excepciones.

+0

No, no lo estoy ignorando. ¿Viste de dónde hablo para que el usuario corrija la dirección de correo electrónico incorrecta? Eso es manejar la excepción. –

+0

No, ya que este es un método de utilidad de nivel inferior, las excepciones definitivamente no deberían manejarse aquí. Déjalo en manos de quienes llaman. –

+0

@Jon: No, su párrafo central resume perfectamente la forma en que se pretendía utilizar las excepciones: si se puede tratar el problema. –

0

Hay una serie de soluciones posibles aquí, y que usted elige depende en gran medida de lo que quiere que suceda.

Lo que necesita es un manejador Try/Catch envuelto alrededor de la funcionalidad en cuestión para atrapar la excepción lanzada y tratar con ella.

Ahora, la cosa es que puede envolverlo todo en una excepción, y detener el correo electrónico por completo, o puede hacerlo por ADDRESS para que 1 mala dirección en una lista de 100 no se rompa el sistema. O puede colocarlo en otro lugar (digamos dónde llama a la función)

4

No debe manejar la excepción. Usted debe manejar (desinfectar) la entrada y asegúrese de que las direcciones de correo electrónico no están mal formados de acuerdo con los requisitos de la Clase MailAddress

aquí es un ejemplo muy básico:

public bool IsValidEmailAddress(string EmailAddress){ 
    Regex regEmail = new Regex(@"^[a-zA-Z0-9][\w\.-]*[a-zA-Z0-9]@[a-zA-Z0-9][\w\.-]*[a-zA-Z0-9]\.[a-zA-Z][a-zA-Z\.]*[a-zA-Z]$"); 

    if(regEmail.IsMatch(EmailAddress)) 
     return true; 

    return false; 
} 

if (IsValidEmailAddress(SenderMail)){ 
    //do stuff to send the mail 
}else{ 
    //return an error to the user interface 
} 
+3

Esto es realmente mucho más difícil de lo que parece. Una de las mejores formas de verificar si hay una dirección de correo electrónico adecuada es intentar crear una dirección de correo electrónico y detectar la excepción. –

+0

¿Estás diciendo que debería dejar de permitir que se suministren datos erróneos a este método? A veces eso no es posible. A veces los datos son generados por seres humanos a través de interfaces de usuario que no están bajo nuestro control ... y luego tenemos que lidiar con argumentos mal formados o inadecuados, en algún lugar ... Y si hay más de un lugar que llama a este método, este método es la última línea de defensa y la última oportunidad para tratar con ellos. –

+0

Vea aquí: http://stackoverflow.com/questions/201323/what-is-the-best-regular-expression-for-validating-email-addresses –

3

El mejor enfoque es asegúrese de que la entrada a SendMessage() esté formateada correctamente de una manera que no cause el lanzamiento de excepciones en primer lugar. Haga alguna validación y comprobación de errores.

En cualquier caso, sin embargo, si fuera a manejarlo, probablemente no lo manejaría en SendMessage. En su lugar, suba un nivel:

public void Submit() { 
    try { 
    SendMessage(emailForm.SenderAddress, emailForm.UserDisplayName, 
     emailForm.RecipientEmails, emailForm.Subject, emailForm.MessageBody); 
    } catch (MailException e) { // Substitute whichever exception is appropriate to catch here. 
    // Tell user that submission failed for specified reasons. 
    } 
} 
6

Cada método solo debe detectar excepciones que realmente puedan manejar. No puedo ver cómo su método SendMail puede hacer algo significativo con una dirección de correo no válida y, por lo tanto, debería permitir que la excepción se propague a la persona que llama.

Cuestiones relacionadas