Ecco come ci avviciniamo al problema:
Tutte le chiamate dal livello di interfaccia utente/codebehind ad altri livelli utilizzare un try-catch, dove abbiamo sempre prendere un eccezione personalizzata. Tutte le azioni eseguite dai livelli sottostanti hanno il loro try-catch, che registra, avvolge e lancia l'eccezione personalizzata. L'interfaccia utente può quindi fare affidamento su questo e cercare le eccezioni gestite con messaggi di errore amichevoli.
Codebehind:
protected void btnSubmit_Click(object sender, EventArgs e)
{
//do something when a button is clicked...
try
{
MyBL.TakeAction()
}
catch(MyApplicationCustomException ex)
{
//display something to the user, etc.
ltlErrorPane.Text = ex.Message;
//or redirect if desired
if(ex.ErrorType == MyCustomErrorsType.Transactional)
{
Response.Redirect("~/Errors/Transaction.aspx");
}
}
}
BL:
Nel livello di business, alcuna operazione che possa fallire l'uso di un try-catch, che registra e avvolge la questione prima di gettarla al UI.
public class MyBL
{
public static void TakeAction()
{
try
{
//do something
}
catch(SpecificDotNetException ex)
{
//log, wrap and throw
MyExceptionManagement.LogException(ex)
throw new MyApplicationCustomException(ex, "Some friendly error message", MyCustomErrorsType.Transactional);
}
finally
{
//clean up...
}
}
}
gestore di eccezioni:
Il gestore di eccezioni attuale ha molteplici modi per registrare, tra cui registro eventi, registro di file ed e-mail, infine, se tutto il resto fallisce. Scegliamo di restituire semplicemente false se il logger non può eseguire nessuna delle azioni previste. IMO questa è una scelta personale però. Riteniamo che la probabilità di 3 metodi falliti in successione (il log degli eventi fallisce, prova il log del file, fallisce, prova la posta elettronica, fallisce) è molto improbabile. In questo caso abbiamo scelto di consentire all'app di continuare. L'altra opzione sarebbe quella di consentire all'app di fallire completamente.
public static class MyExceptionManagement
{
public static bool LogException(Exception ex)
{
try
{
//try logging to a log source by priority,
//if it fails with all sources, return false as a last resort
//we choose not to let logging issues interfere with user experience
//if logging worked
return true;
}
catch(Exception ex)
{
//in most cases, using try-catch as a true-false is bad practice
//but when logging an exception causes an exception itself, we do
//use this as a well-considered choice.
return false;
}
}
}
Infine, come una cassetta di sicurezza fail-, noi non implementare il gestore di eventi globale Application_Error
(in Global.asax
). Questa è l'ultima risorsa per i casi in cui non abbiamo provato correttamente a catturare qualcosa. Generalmente effettuiamo il log e il reindirizzamento a una pagina di errore amichevole. Se la gestione degli errori personalizzati di cui sopra viene eseguita correttamente, pochissimi errori lo faranno al gestore globale.
Spero che questo possa aiutare un po '. È una soluzione possibile. Ha funzionato molto bene per noi per diversi anni su alcune applicazioni più grandi.
Si spera che questo sia solo uno pseudo-codice, ma probabilmente non dovresti prendere nemmeno un'eccezione generica. –
Va bene catturare un'eccezione generica come un catch-all, purché tu abbia tentato di rilevare prima eccezioni specifiche (dato che puoi avere più rilevazioni per prova) ... Il solo sopra si dovrebbe essere più specifico ... –
Per quello che vale, vorrei prima registrare l'errore. Se Transaction.voidorder ha un'eccezione, non hai record di –