2009-12-29 16 views
5

Sono relativamente nuovo per C# e .NET e sto cercando di imparare a gestire meglio le eccezioni nel mio codice.Come devo gestire le eccezioni in questa funzione C#?

Prendere la seguente funzione che ho scritto, ad esempio:

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

Se si tenta di aggiungere un indirizzo email che non è valido in Message.From o Message.To, sarà un'eccezione. In questo momento la mia app si blocca e brucia quando questo accade.

Qualcuno mi può mostrare il modo appropriato per gestire tale eccezione in questo metodo?

risposta

18

Questo è il modo appropriato per gestire le eccezioni!

In generale, un'eccezione non devono essere manipolati meno che il problema può essere risolto, e dovrebbe essere trattate solo in un luogo in cui può essere applicata la correzione.

Per esempio, il chiamante del codice potrebbe desiderare di richiedere all'utente di correggere l'indirizzo e-mail male. Ma il tuo codice non può sapere il modo giusto per richiedere. Vieni chiamato da WinForms o Web Form? Come dovrebbe apparire la finestra di dialogo? Dovrebbe anche essere una finestra di dialogo? Queste sono cose che possono essere conosciute solo dal chiamante del tuo metodo, e non dal tuo stesso metodo.


Nella chiamante:

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

Si noti che tutte le eccezioni diverse da MyMailAddressException si propagheranno al codice che sa come gestirli.


adeguato livello di "trattamento" nel metodo:

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

Il chiamante può quindi catturare MyMailAddressException ed avere tutte le informazioni necessarie per dire all'utente cosa sistemare. Altre eccezioni dovrebbero propagarsi.


Le mie precedenti modifiche hanno indirizzato la domanda sul metodo. Presumo che la tua applicazione abbia una gestione delle eccezioni di alto livello appropriata. Gabriel mi fa notare che se avessi una gestione delle eccezioni di primo livello appropriata, la tua applicazione non andrebbe in crash!

Tuttavia, crash non è necessariamente una cosa negativa. Se succede qualcosa che il tuo codice non può gestire, allora l'arresto anomalo è la cosa giusta da fare. L'alternativa è provare a continuare a correre, sperando che questa eccezione non gestita non abbia danneggiato il tuo programma in modo tale che inizi a produrre risultati errati.

Le specifiche di esattamente dove mettere "i gestori di alto livello" dipende dal vostro programma. Ad esempio, è diverso tra WinForms e le applicazioni ASP.NET. Tuttavia, il concetto sarà lo stesso: registrare in sicurezza tutte le informazioni disponibili, quindi consentire l'propagazione dell'eccezione, causando il blocco dell'applicazione.

Ovviamente, è necessario utilizzare i blocchi finally per pulire l'applicazione, anche in presenza di eccezioni.

+0

No, non lo sto ignorando. Hai visto dove parlo chiedendo all'utente di correggere l'indirizzo email errato? Gestisce l'eccezione. –

+0

No, poiché questo è un metodo di utilità di livello inferiore, le eccezioni dovrebbero assolutamente essere _non_ qui gestite. Lascia fare ai chiamanti. –

+0

@Jon: No, il suo paragrafo intermedio riassume perfettamente il modo in cui le eccezioni erano destinate a essere utilizzate: se il problema può essere risolto. –

0

Qui ci sono un certo numero di soluzioni possibili e che si scelgono dipende in gran parte da ciò che si vuole accadere.

Quello che ti serve è un gestore Try/Catch avvolto attorno alla funzionalità in questione per catturare l'eccezione generata e gestirla.

Ora, il fatto è che è possibile avvolgere tutto in un'eccezione e interrompere completamente l'e-mail oppure è possibile farlo su una base di TO ADDRESS in modo che 1 indirizzo non valido in un elenco di 100 non si interrompa il sistema. OPPURE puoi posizionarlo altrove (ad esempio, dove si chiama la funzione)

4

Non si deve gestire l'eccezione. Si dovrebbe gestire (disinfettare) l'ingresso e fare in modo che gli indirizzi email non malformati corrisponde alle esigenze della classe MailAddress

ecco un esempio molto semplice:

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

Questo è in realtà molto più difficile di quanto sembri. Uno dei modi migliori per verificare la correttezza di un indirizzo e-mail è provare a creare un indirizzo mail e rilevare l'eccezione. –

+0

Stai dicendo che dovrebbe semplicemente smettere di fornire dati sbagliati a questo metodo? A volte questo non è possibile. A volte i dati sono generati da esseri umani attraverso interfacce utente che non sono sotto il nostro controllo ... e poi dobbiamo affrontare argomenti malformati o inadeguati - da qualche parte ... E se c'è più di un posto che chiama questo methoid, questo metodo è l'ultima linea di difesa e l'ultima opportunità per affrontarli. –

+0

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

3

L'approccio migliore è quello di assicurati che l'input su SendMessage() sia formattato correttamente in modo tale da non generare eccezioni in primo luogo. Effettuare alcune convalide e controllo degli errori.

In ogni caso, tuttavia, se lo si dovesse gestire, probabilmente non lo si gestirà in SendMessage. Invece, salire di un livello:

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

Ogni metodo deve rilevare solo eccezioni che possono effettivamente gestire. Non riesco a vedere come il tuo metodo SendMail possa fare qualcosa di significativo con un indirizzo di posta non valido e quindi dovrebbe semplicemente far propagare l'eccezione al chiamante.

Problemi correlati