.NET: quale eccezione generare quando manca un'impostazione di configurazione richiesta?


123

Ecco uno scenario standard:

if(string.IsNullOrEmpty(Configuration.AppSettings["foobar"]))
   throw new SomeStandardException("Application not configured correctly, bozo.");

Il problema è che non sono del tutto sicuro di quale eccezione SomeStandardExceptiondebba essere.

Ho esaminato attentamente il Framework 3.5 e ho trovato due probabili candidati: ConfigurationExceptione ConfigurationErrorsException.

System.Configuration.ConfigurationException

Eccezione generata quando si è verificato un errore di sistema di configurazione.

Osservazioni

L' ConfigurationExceptioneccezione viene generata se l'applicazione tenta di leggere o scrivere dati nel file di configurazione ma non riesce. Alcuni possibili motivi possono includere XML non valido nel file di configurazione, problemi di autorizzazione del file e proprietà di configurazione con valori non validi.

Nota:

L' ConfigurationExceptionoggetto viene mantenuto per compatibilità con le versioni precedenti. L' ConfigurationErrorsException oggetto lo sostituisce per il sistema di configurazione.

Questa eccezione in realtà sembra perfetta per ciò di cui ho bisogno, ma è stata contrassegnata come obsoleta, quindi, ixnay su atthay.

Questo ci porta al più sconcertante ConfigurationErrorsException:

System.Configuration.ConfigurationErrorsException

Il valore corrente non è uno dei valori EnableSessionState.

Come puoi vedere, la sua documentazione è completamente inutile. (È così sia nella guida locale che in linea.) Un esame della classe stessa mostra che è eccessivo per quello che voglio.

In poche parole, ho bisogno di un'eccezione standard che dovrebbe essere generata quando un'impostazione di configurazione dell'applicazione manca o contiene un valore non valido. Penseresti che il Framework avesse un'eccezione del genere incorporata per le applicazioni da utilizzare. (Apparentemente lo ha fatto, ma è stato contrassegnato come obsoleto ed è stato sostituito da qualcosa di molto più ampio.)

Quali soluzioni, se ce ne sono, state usando per questo, e dovrò succhiarlo e tirare la mia eccezione per questo?

Modifica addenda

Alcuni hanno chiesto se potevo fornire un valore predefinito e continuare. In alcuni casi, sì, e in quei casi, l'eccezione non verrebbe generata. Tuttavia, per alcune impostazioni, questo non si applica. Ad esempio: nomi e credenziali del server di database, server di autenticazione e percorsi per le applicazioni di terze parti installate.

Vale anche la pena notare che l'applicazione su cui sto lavorando principalmente è un'applicazione console in esecuzione in modalità batch e voglio che generi un'eccezione che viene rilevata dal metodo principale e registrata in modo appropriato se la cosa non è configurata in modo appropriato. (È un codice legacy che ho ereditato e attualmente presume che tutto sia peachy.)


1
Documentazione per System.Configuration.ConfigurationErrorsException è stata aggiornata.
slolife

Risposte:


36

Non sei limitato nel lanciare eccezioni alle eccezioni esistenti nel Framework. Se decidi di utilizzare le eccezioni esistenti, non devi assolutamente seguire la documentazione alla lettera. La documentazione descriverà come il framework utilizza una data eccezione, ma non implica alcuna limitazione su come si sceglie di utilizzare / riutilizzare un'eccezione esistente.

È la tua applicazione: fintanto che la documenti e indichi chiaramente l'eccezione che verrà lanciata nel caso specifico di un valore di configurazione mancante, puoi usare qualsiasi eccezione tu voglia. Se desideri un'indicazione molto specifica di un valore mancante , potresti prendere in considerazione la possibilità di scrivere la tua eccezione ConfigurationSettingMissing:

[Serializable]
public class ConfigurationMissingException : ConfigurationErrorsException
{}

MODIFICA: scrivere la tua eccezione in questo caso porta il vantaggio aggiuntivo di garantire che non ci sarà mai alcuna confusione riguardo alla provenienza dell'eccezione: il framework o la tua applicazione. Il framework non genererà mai le eccezioni personalizzate.

AGGIORNAMENTO: Sono d'accordo con i commenti, quindi ho cambiato la sottoclasse in ConfigurationErrorsException da Exception. Penso che sia generalmente una buona idea sottoclassare le eccezioni personalizzate dalle eccezioni Framework esistenti, ove possibile, evitando la classe Exception a meno che non sia necessaria un'eccezione specifica dell'applicazione.


17
Sono in qualche modo in disaccordo. Se hai intenzione di utilizzare un'eccezione esistente, dovrebbe essere usata ESATTAMENTE come la documentazione dice che è usata, altrimenti confonderai coloro che verranno dopo di te. Se hai intenzione di fare qualcosa di diverso, crea la tua eccezione, come hai detto.
Robert C. Barth

1
Non sono d'accordo. A meno che non si disponga di uno scenario per rilevare l'eccezione personalizzata, improbabile nel caso di un errore di configurazione, è meglio riutilizzare un tipo esistente (ConfigurationErrorsException). E se crei un tipo personalizzato, lo deriverei da un tipo correlato come ConfigurationErrorsException.
Joe

@Robert & Joe- Non sto suggerendo che le eccezioni Framework esistenti debbano essere utilizzate in modo incoerente con la loro funzione prevista, solo che c'è una certa flessibilità fintanto che il caso specifico (valore mancante) si adatta al caso generale (ConfigurationErrorsException).
Dave Swersky,

1
Potrebbero verificarsi problemi se si genera l'eccezione all'interno di un'applicazione ASP.NET poiché ConfigurationErrorsException e le classi derivate da essa non vengono rilevate nel metodo OnError protetto o dall'evento Global ASAX Error. Vedi questa domanda che ho pubblicato .... stackoverflow.com/questions/25299325/…
Mick

48

Personalmente, userei InvalidOperationException , poiché è un problema con lo stato dell'oggetto, non il sistema di configurazione. Dopo tutto, non dovresti permettere che queste impostazioni siano impostate dal codice e non anche dalla configurazione? La parte importante qui non è che non ci fosse alcuna riga in app.config, ma che non fosse presente un'informazione richiesta.

Per me, ConfigurationException (e la sua sostituzione, ConfigurationErrorsException - nonostante i documenti MSDN fuorvianti) sono per errori nel salvataggio, nella lettura, ecc. Della configurazione.


Ho optato per InvalidOperationException, poiché è gestita dal metodo OnError protetto da pagina ASP.NET, mentre ConfigurationErrorsException e tutte le eccezioni da esso derivate non lo sono
Mick

2
Questo mi sorprenderebbe davvero se ottengo un'eccezione InvalidOperationException se ottengo la configurazione sbagliata.
keuleJ

18

Come ha detto Daniel Richardson, ConfigurationErrorsException è quello da usare. In generale, si consiglia di creare i propri tipi di eccezione personalizzati solo se si dispone di uno scenario per gestirli. Nel caso di errori di configurazione, che di solito sono fatali, questo è raramente il caso, quindi di solito è più appropriato riutilizzare il tipo di ConfigurationErrorsException esistente.

Prima di .NET 2.0, la raccomandazione era di utilizzare System.Configuration.ConfigurationException . ConfigurationException è diventato obsoleto in .NET 2.0, per motivi che non mi sono mai stati chiari, e la raccomandazione è cambiata per utilizzare ConfigurationErrorsException.

Utilizzo un metodo di supporto per generare l'eccezione in modo che sia facile modificare l'eccezione generata in un unico punto durante la migrazione da .NET 1.x a 2.0 o se Microsoft decide di modificare nuovamente la raccomandazione:

if(string.IsNullOrEmpty(Configuration.AppSettings("foobar")))
{
   throw CreateMissingSettingException("foobar");
}

...

private static Exception CreateMissingSettingException(string name)
{
    return new ConfigurationErrorsException(
        String.Format
        (
        CultureInfo.CurrentCulture,
        Properties.Resources.MissingConfigSetting,
        name
        )
        );
}


7

ConfigurationErrorsExceptionè l'eccezione corretta da lanciare nella situazione che descrivi. Una versione precedente della documentazione MSDN per ConfigurationErrorsExceptionha più senso.

http://msdn.microsoft.com/en-us/library/system.configuration.configurationerrorsexception(VS.80).aspx

Il riepilogo e le osservazioni precedenti di MSDN sono:

  • Eccezione generata quando si è verificato un errore del sistema di configurazione.
  • L' ConfigurationErrorsException eccezione viene generata quando si verifica un errore durante la lettura o la scrittura delle informazioni di configurazione.

7
dalla documentazione: "Questa API supporta l'infrastruttura del prodotto e non deve essere utilizzata direttamente dal codice. Inizializza una nuova istanza della classe ConfigurationErrorsException."
Oleg Sh

6

La classe ConfigurationElement (che è la classe base di molte classi relative alla configurazione, come ConfigurationSection) ha un metodo chiamato OnRequiredPropertyNotFound (ci sono anche altri metodi di supporto). Puoi forse chiamarli.

OnRequiredPropertyNotFound è implementato in questo modo:

protected virtual object OnRequiredPropertyNotFound(string name) {
    throw new ConfigurationErrorsException(SR.GetString("Config_base_required_attribute_missing", new object[] { name }), this.PropertyFileName(name), this.PropertyLineNumber(name)); }

1

Lo succhierei e lo faccio da solo ... ma prima di farlo, è possibile che il sistema assuma un valore predefinito per questa impostazione di configurazione? In genere cerco di farlo per ogni impostazione che potrebbe sfuggire alla gente di Ops Management ... (o forse dovrei dire, per quante più impostazioni possibili - per alcuni è chiaramente non appropriato che il sistema prenda una decisione predefinita. ..)

in generale un'eccezione personalizzata non è un grande sforzo ... ecco un esempio ...

[Serializable]
public class MyCustomApplicationException : ApplicationException
{
    #region privates
    #endregion privates

    #region properties
    #endregion properties

    public MyCustomApplicationException (string sMessage,
        Exception innerException)
        : base(sMessage, innerException) { }
    public MyCustomApplicationException (string sMessage)
        : base(sMessage) { }
    public MyCustomApplicationException () { }

    #region Serializeable Code
    public MyCustomApplicationException (
       SerializationInfo info, StreamingContext context)
        : base(info, context) { }
    #endregion Serializeable Code
}

2
MSDN: ... un'applicazione che deve creare le proprie eccezioni, [...] derivare eccezioni personalizzate dalla classe Exception. Inizialmente si pensava che le eccezioni personalizzate dovessero derivare dalla classe ApplicationException; tuttavia, in pratica, non è stato riscontrato che ciò aggiunga valore significativo.
Gaspar Nagy

Sì, penso che sia stato perché i programmatori MS che hanno codificato il framework hanno derivato numerose eccezioni CLR da ApplicationException, distruggendo così il significato della distinzione .. Lo faccio ancora però, poiché non vedo alcun danno in esso ...
Charles Bretana

1

Un metodo alternativo che potresti utilizzare per i tuoi file di configurazione sarebbe utilizzare sezioni di configurazione personalizzate invece di AppSettings. In questo modo puoi specificare che una proprietà IsRequirede il sistema di configurazione gestiranno questo controllo per te. Se la proprietà è mancante, lancerà un ConfigurationErrorsExceptionquindi suppongo che supporti la risposta che dovresti usare quell'eccezione nel tuo caso.


0

La mia regola generale sarebbe:

  1. Se il caso della configurazione mancante non è molto comune e credo che non vorrei mai gestire questo caso in modo diverso rispetto ad altre eccezioni, utilizzo semplicemente la classe "Eccezione" di base con un messaggio appropriato:

    lancia una nuova eccezione ("il mio messaggio qui")

  2. Se voglio o penso che ci sia un'alta probabilità che vorrei trattare questo caso in un modo diverso rispetto alla maggior parte delle altre eccezioni, sceglierei il mio tipo come le persone hanno già suggerito qui.


0

Tendo a non essere d'accordo con la premessa della tua domanda:

In poche parole, ho bisogno di un'eccezione standard che dovrebbe essere generata quando un'impostazione di configurazione dell'applicazione manca o contiene un valore non valido. Penseresti che il Framework avesse un'eccezione del genere incorporata per le applicazioni da utilizzare. (Apparentemente lo ha fatto, ma è stato contrassegnato come obsoleto ed è stato sostituito da qualcosa di molto più ampio.)

Secondo la documentazione MSDN su System.Exception ( Exception Class , in realtà non dovresti generare eccezioni per errori di input dell'utente, per motivi di prestazioni (che è stato sottolineato da altri su Stack Overflow e altrove). Questo sembra avere senso come beh, perché la tua funzione non può restituire false se l'input dell'utente è inserito in modo errato e quindi l'applicazione si chiude con garbo? Questo sembra essere più un problema di progettazione che un problema con quale eccezione lanciare.

Come altri hanno fatto notare, se davvero avete a generato un'eccezione - per qualsiasi motivo - non v'è alcuna ragione per cui non è possibile definire il tipo di eccezione ereditando da System.Exception.


2
Perché esattamente le prestazioni sarebbero importanti in questo scenario specifico? IUC, quindi l'eccezione viene lanciata esattamente una volta e il processo probabilmente si interrompe comunque in seguito (ovviamente, dopo aver mostrato un bel pop-up all'utente). (continua ...)

2
Restituire un codice di errore invece di lanciare un'eccezione potrebbe essere doloroso, perché dovresti quindi propagare le informazioni sull'errore da solo nello stack di chiamate. È necessario utilizzare le eccezioni per errori relativamente rari che potrebbero essere propagati su più stack frame. Entrambi si applicano qui.

1
Ti sei perso qualcosa: "quando un'impostazione di configurazione dell'applicazione manca o contiene un valore non valido", non è la stessa cosa di un input utente errato. Questa è una configurazione di base che manca. Dovrebbe essere un'eccezione personalizzata e dovrebbe interrompere l'esecuzione dell'app.
jcollum

2
In questa particolare applicazione, è quasi interamente guidato dalle impostazioni nel file di configurazione. Se le impostazioni non sono presenti (dove sono crittografate), l'applicazione non può continuare e deve terminare. È virtualmente necessaria un'eccezione.
Mike Hofer

1
Questo può certamente entrare nella semantica e la struttura del codice ovviamente detterà la migliore implementazione per la tua situazione. Tuttavia, se tu avessi libero sfogo nel design, sceglierei comunque un oggetto per registrare l'errore e un'uscita graziosa su un'eccezione, le prestazioni sono un problema o meno.
Matt Jordan

-2

Potresti provare a ereditare l'eccezione XML o semplicemente usarla.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.