Domanda

Devo rilevare le eccezioni a scopo di registrazione?

public foo(..)
{
   try
   {
     ...
   } catch (Exception ex) {
     Logger.Error(ex);
     throw;
   }
}

Se questo è attivo in ciascuno dei miei livelli (DataAccess, Business e WebService), significa che l'eccezione viene registrata più volte.

Ha senso farlo se i miei livelli si trovano in progetti separati e solo le interfacce pubbliche contengono try/catch?Perché?Perché no?C'è un approccio diverso che potrei usare?

È stato utile?

Soluzione

Sicuramente no.Dovresti trovare il posto giusto maniglia l'eccezione (in realtà fai qualcosa, come catch-and-not-rethrow), quindi registrala.Ovviamente puoi e dovresti includere l'intera traccia dello stack, ma seguire il tuo suggerimento sporcherebbe il codice con blocchi try-catch.

Altri suggerimenti

A meno che non si intenda modificare l'eccezione, è necessario accedere solo al livello in cui si intende gestire l'errore e non riproporlo.Altrimenti il ​​tuo registro avrà solo un mucchio di "rumore", 3 o più dello stesso messaggio registrato, una volta per ogni livello.

La mia migliore pratica è:

  1. Try/catch solo nei metodi pubblici (in generale;ovviamente se stai rilevando un errore specifico lo controllerai lì)
  2. Accedi al livello dell'interfaccia utente solo subito prima di eliminare l'errore e reindirizzare a una pagina/modulo di errore.

La regola generale è che si coglie un'eccezione solo se si può effettivamente fare qualcosa al riguardo.Pertanto, a livello aziendale o dati, potresti rilevare l'eccezione solo in situazioni come questa:

            try
            {
                this.Persist(trans);
            }
            catch(Exception ex)
            {
                trans.Rollback();
                throw ex;
            }

Il livello My Business/Dati tenta di salvare i dati: se viene generata un'eccezione, viene eseguito il rollback di tutte le transazioni e l'eccezione viene inviata al livello UI.

A livello dell'interfaccia utente, puoi implementare un gestore di eccezioni comune:

Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);

Che poi gestisce tutte le eccezioni.Potrebbe registrare l'eccezione e quindi visualizzare una risposta intuitiva:

    static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
    {
        LogException(e.Exception);
    }
    static void LogException(Exception ex)
    {
        YYYExceptionHandling.HandleException(ex,
            YYYExceptionHandling.ExceptionPolicyType.YYY_Policy,
            YYYExceptionHandling.ExceptionPriority.Medium,
            "An error has occurred, please contact Administrator");
    } 

Nel codice dell'interfaccia utente effettivo, puoi rilevare singole eccezioni se intendi fare qualcosa di diverso, ad esempio visualizzare un messaggio amichevole diverso o modificare lo schermo, ecc.

Inoltre, giusto come promemoria, prova sempre a gestire gli errori, ad esempio dividere per 0, anziché generare un'eccezione.

È buona pratica farlo tradurre le eccezioni.Non limitarti a registrarli.Se vuoi conoscere il motivo specifico per cui è stata lanciata un'eccezione, lancia eccezioni specifiche:

public void connect() throws ConnectionException {
   try {
       File conf = new File("blabla");
       ...
   } catch (FileNotFoundException ex) {
       LOGGER.error("log message", ex);
       throw new ConnectionException("The configuration file was not found", ex);
   }
}

Utilizza le tue eccezioni per racchiudere l'eccezione inbuild.In questo modo è possibile distinguere tra errori noti e sconosciuti quando si rileva un'eccezione.Questo è utile se hai un metodo che chiama altri metodi che probabilmente generano eccezioni per reagire a fallimenti attesi e imprevisti

potresti voler cercare gli stili standard di gestione delle eccezioni, ma la mia comprensione è questa:gestire le eccezioni al livello in cui puoi aggiungere ulteriori dettagli all'eccezione o al livello in cui presenterai l'eccezione all'utente.

nel tuo esempio non stai facendo altro che catturare l'eccezione, registrarla e lanciarla di nuovo.perché non catturarlo semplicemente al livello più alto con un try/catch invece che all'interno di ogni metodo se tutto ciò che stai facendo è registrarlo?

lo gestirei a quel livello solo se aggiungessi alcune informazioni utili all'eccezione prima di lanciarla di nuovo: avvolgi l'eccezione in una nuova eccezione creata che contenga informazioni utili oltre il testo dell'eccezione di basso livello che di solito significa poco per chiunque senza alcun contesto..

A volte è necessario registrare dati che non sono disponibili nel luogo in cui viene gestita l'eccezione.In tal caso, è opportuno effettuare il login solo per ottenere tali informazioni.

Ad esempio (pseudocodice Java):

public void methodWithDynamicallyGeneratedSQL() throws SQLException {
    String sql = ...; // Generate some SQL
    try {
        ... // Try running the query
    }
    catch (SQLException ex) {
        // Don't bother to log the stack trace, that will
        // be printed when the exception is handled for real
        logger.error(ex.toString()+"For SQL: '"+sql+"'");
        throw ex;  // Handle the exception long after the SQL is gone
    }
}

Questo è simile alla registrazione retroattiva (la mia terminologia), in cui si memorizza nel buffer un registro di eventi ma non li si scrive a meno che non si verifichi un evento trigger, ad esempio viene generata un'eccezione.

Se ti viene richiesto di registrare tutte le eccezioni, allora è un'idea fantastica.Detto questo, registrare tutte le eccezioni senza un altro motivo non è una buona idea.

Potresti voler accedere al livello più alto, che di solito è l'interfaccia utente o il codice del servizio web.Registrarsi più volte è una specie di spreco.Inoltre, vuoi conoscere l'intera storia quando guardi il registro.

In una delle nostre applicazioni, tutte le nostre pagine derivano da un oggetto BasePage e questo oggetto gestisce la gestione delle eccezioni e la registrazione degli errori.

Se questa è l'unica cosa che fa, penso che sia meglio rimuovere try/catch da quelle classi e lasciare che l'eccezione venga sollevata alla classe responsabile della loro gestione.In questo modo ottieni solo un log per eccezione, offrendo log più chiari e anche tu puoi registrare lo stacktrace in modo da non perdere il punto in cui è stata originata l'eccezione.

Il mio metodo è registrare le eccezioni solo nel gestore.Il "vero" gestore, per così dire.Altrimenti il ​​log sarà molto difficile da leggere e il codice meno strutturato.

Dipende dall'eccezione:se ciò effettivamente non dovesse accadere, lo registrerei sicuramente.D'altro canto:se ti aspetti questa eccezione dovresti pensare al design dell'applicazione.

In entrambi i casi:dovresti almeno provare a specificare l'eccezione che vuoi rilanciare, catturare o registrare.

public foo(..)
{
   try
   {
     ...
   }
   catch (NullReferenceException ex) {
     DoSmth(e);
   }
   catch (ArgumentExcetion ex) {
     DoSmth(e);
   }
   catch (Exception ex) {
     DoSmth(e);
   }
}

Ti consigliamo di accedere al limite di un livello.Ad esempio, se il livello aziendale può essere distribuito su un computer fisicamente separato in un'applicazione a più livelli, è opportuno registrare e generare l'errore in questo modo.

In questo modo hai un registro delle eccezioni sul server e non hai bisogno di frugare tra le macchine client per scoprire cosa è successo.

Utilizzo questo modello nei livelli aziendali di applicazioni che utilizzano servizi Web remoti o ASMX.Con WCF puoi intercettare e registrare un'eccezione utilizzando un IErrorHandler collegato al tuo ChannelDispatcher (un altro argomento completamente), quindi non è necessario il modello try/catch/throw.

È necessario sviluppare una strategia per la gestione delle eccezioni.Non consiglio il prendi e rilancia.Oltre alle voci di registro superflue, ciò rende il codice più difficile da leggere.Considera la possibilità di scrivere nel log nel costruttore per l'eccezione.Questo riserva try/catch per le eccezioni da cui vuoi recuperare;rendendo il codice più facile da leggere.Per gestire eccezioni impreviste o irrecuperabili, potresti volere un try/catch vicino allo strato più esterno del programma per registrare le informazioni diagnostiche.

A proposito, se si tratta di C++, il tuo blocco catch sta creando una copia dell'oggetto eccezione che può essere una potenziale fonte di ulteriori problemi.Prova a catturare un riferimento al tipo di eccezione:

  catch (const Exception& ex) { ... }

Questo Il podcast di Software Engineering Radio è un ottimo riferimento per le migliori pratiche nella gestione degli errori.In realtà ci sono 2 lezioni.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top