.NET: Welche Ausnahme muss ausgelöst werden, wenn eine erforderliche Konfigurationseinstellung fehlt?

123

Hier ist ein Standardszenario:

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

Das Problem ist, ich bin nicht ganz sicher, welche Ausnahme SomeStandardExceptionsein sollte.

Ich habe das 3.5 Framework durchgesehen und zwei wahrscheinliche Kandidaten gefunden: ConfigurationExceptionund ConfigurationErrorsException.

System.Configuration.ConfigurationException

Die Ausnahme, die ausgelöst wird, wenn ein Konfigurationssystemfehler aufgetreten ist.

Bemerkungen

Die ConfigurationExceptionAusnahme wird ausgelöst, wenn die Anwendung versucht, Daten in die Konfigurationsdatei zu lesen oder zu schreiben, dies jedoch nicht erfolgreich ist. Einige mögliche Gründe hierfür können fehlerhaftes XML in der Konfigurationsdatei, Dateiberechtigungsprobleme und Konfigurationseigenschaften mit ungültigen Werten sein.

Hinweis:

Das ConfigurationExceptionObjekt wird aus Gründen der Abwärtskompatibilität beibehalten. Das ConfigurationErrorsException Objekt ersetzt es für das Konfigurationssystem.

Diese Ausnahme klingt eigentlich perfekt für das, was ich brauche, aber sie wurde als veraltet markiert, also ixnay on atthay.

Dies bringt uns zu dem durchaus rätselhaften ConfigurationErrorsException:

System.Configuration.ConfigurationErrorsException

Der aktuelle Wert ist keiner der EnableSessionState-Werte.

Wie Sie sehen können, ist die Dokumentation völlig nutzlos. (Dies ist sowohl in der lokalen als auch in der Online-Hilfe der Fall.) Eine Untersuchung der Klasse selbst zeigt, dass es für das, was ich will, ein drastischer Overkill ist.

Kurz gesagt, ich benötige eine Standardausnahme, die ausgelöst werden sollte, wenn eine Anwendungskonfigurationseinstellung fehlt oder einen ungültigen Wert enthält. Sie würden denken, dass das Framework eine solche Ausnahme für Anwendungen enthält. (Anscheinend, aber es wurde als veraltet markiert und durch etwas viel Größeres ersetzt.)

Welche Lösungen, wenn überhaupt, benutzt ihr dafür, und muss ich es aufsaugen und meine eigene Ausnahme dafür rollen?

Nachträge bearbeiten

Einige haben gefragt, ob ich einen Standardwert angeben könnte oder nicht, und fahren fort. In bestimmten Fällen ja, und in diesen Fällen wird die Ausnahme nicht ausgelöst. Für bestimmte Einstellungen gilt dies jedoch nicht. Zum Beispiel: Datenbankservernamen und -anmeldeinformationen, Authentifizierungsserver und Pfade zu installierten Anwendungen von Drittanbietern.

Es ist auch erwähnenswert, dass die Anwendung, an der ich hauptsächlich arbeite, eine Konsolenanwendung ist, die im Batch-Modus ausgeführt wird, und ich möchte, dass sie eine Ausnahme auslöst, die von der Hauptmethode abgefangen und entsprechend protokolliert wird, wenn das Objekt nicht ordnungsgemäß konfiguriert ist. (Es ist Legacy-Code, den ich geerbt habe und der derzeit nur davon ausgeht, dass alles pfirsichfarben ist.)

Mike Hofer
quelle
1
Die Dokumentation für System.Configuration.ConfigurationErrorsException wurde aktualisiert.
Slolife

Antworten:

36

Sie sind beim Auslösen von Ausnahmen nicht auf vorhandene Ausnahmen im Framework beschränkt. Wenn Sie sich dafür entscheiden, vorhandene Ausnahmen zu verwenden, müssen Sie die Dokumentation nicht unbedingt genau befolgen. Die Dokumentation wird beschrieben , wie der Rahmen eine gegebene Ausnahme verwendet, aber bedeutet keine Einschränkung, wie Sie zur Verwendung / Wiederverwendung einer bestehenden Ausnahme wählen.

Es ist Ihre Anwendung. Solange Sie sie dokumentieren und die Ausnahme, die im speziellen Fall eines fehlenden Konfigurationswerts ausgelöst wird, klar angeben, können Sie eine beliebige Ausnahme verwenden. Wenn Sie einen ganz bestimmten Hinweis auf einen fehlenden Wert wünschen , können Sie eine eigene ConfigurationSettingMissing-Ausnahme schreiben:

[Serializable]
public class ConfigurationMissingException : ConfigurationErrorsException
{}

BEARBEITEN: Das Schreiben einer eigenen Ausnahme in diesem Fall bietet den zusätzlichen Vorteil, dass garantiert wird, dass keine Verwirrung darüber besteht, woher die Ausnahme stammt - aus dem Framework oder Ihrer Anwendung. Das Framework wird niemals Ihre benutzerdefinierten Ausnahmen auslösen.

UPDATE: Ich stimme den Kommentaren zu, daher habe ich die Unterklasse von Exception in ConfigurationErrorsException geändert. Ich denke, es ist im Allgemeinen eine gute Idee, benutzerdefinierte Ausnahmen von vorhandenen Framework-Ausnahmen nach Möglichkeit zu unterordnen und die Exception-Klasse zu vermeiden, es sei denn, Sie benötigen eine anwendungsspezifische Ausnahme.

Dave Swersky
quelle
17
Ich bin etwas anderer Meinung. Wenn Sie eine vorhandene Ausnahme verwenden, sollte sie GENAU verwendet werden, da in der Dokumentation angegeben ist, dass sie verwendet wird. Andernfalls werden Sie diejenigen verwirren, die nach Ihnen kommen. Wenn Sie etwas anderes tun möchten, erstellen Sie einfach Ihre eigene Ausnahme, wie Sie gesagt haben.
Robert C. Barth
1
Ich bin nicht einverstanden. Sofern Sie kein Szenario zum Abfangen Ihrer benutzerdefinierten Ausnahme haben, das im Falle eines Konfigurationsfehlers unwahrscheinlich ist, ist es besser, einen vorhandenen Typ (ConfigurationErrorsException) wiederzuverwenden. Und wenn Sie einen benutzerdefinierten Typ erstellen, würde ich ihn von einem verwandten Typ wie ConfigurationErrorsException ableiten.
Joe
@Robert & Joe- Ich schlage nicht vor, dass vorhandene Framework-Ausnahmen inkonsistent mit ihrer beabsichtigten Funktion verwendet werden sollten, nur dass es eine gewisse Flexibilität gibt, solange der spezifische Fall (fehlender Wert) mit dem allgemeinen Fall (ConfigurationErrorsException) übereinstimmt.
Dave Swersky
1
Dies kann zu Problemen führen, wenn Sie die Ausnahme in einer ASP.NET-Anwendung als ConfigurationErrorsException auslösen und daraus abgeleitete Klassen nicht in der geschützten OnError-Methode oder vom Global ASAX Error-Ereignis erfasst werden. Siehe diese Frage, die ich gepostet habe .... stackoverflow.com/questions/25299325/…
Mick
48

Persönlich würde ich InvalidOperationException verwenden , da dies ein Problem mit dem Objektstatus ist - nicht mit dem Konfigurationssystem. Sollten Sie nicht zulassen, dass diese Einstellungen durch Code und nicht auch durch Konfiguration festgelegt werden? Der wichtige Teil hier ist nicht, dass es in app.config keine Zeile gab, sondern dass eine erforderliche Information nicht vorhanden war.

Für mich ist ConfigurationException (und deren Ersatz ConfigurationErrorsException - trotz der irreführenden MSDN-Dokumente) für Fehler beim Speichern, Lesen usw. der Konfiguration gedacht.

Mark Brackett
quelle
Ich habe mich für InvalidOperationException entschieden, da diese von der ASP.NET Page-geschützten OnError-Methode verarbeitet wird, während ConfigurationErrorsException und alle daraus abgeleiteten Ausnahmen nicht
Mick
2
Das würde mich wirklich überraschen, wenn ich eine InvalidOperationException bekomme, wenn ich die falsche Konfiguration bekomme.
KeuleJ
18

Wie Daniel Richardson sagte, ConfigurationErrorsException die zu verwendende. Im Allgemeinen wird nur empfohlen, eigene benutzerdefinierte Ausnahmetypen zu erstellen, wenn Sie über ein Szenario verfügen, um diese zu behandeln. Bei Konfigurationsfehlern, die normalerweise schwerwiegend sind, ist dies selten der Fall. Daher ist es normalerweise besser, den vorhandenen ConfigurationErrorsException-Typ wiederzuverwenden.

Vor .NET 2.0 wurde empfohlen, System.Configuration.ConfigurationException zu verwenden . ConfigurationException wurde in .NET 2.0 aus Gründen, die mir nie klar waren, veraltet, und die Empfehlung wurde geändert, um ConfigurationErrorsException zu verwenden.

Ich verwende eine Hilfsmethode, um die Ausnahme auszulösen, damit es einfach ist, die Ausnahme, die an einer Stelle ausgelöst wird, zu ändern, wenn von .NET 1.x auf 2.0 migriert wird oder wenn Microsoft beschließt, die Empfehlung erneut zu ändern:

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
        )
        );
}
Joe
quelle
16

Was ist mit System.Configuration.SettingsPropertyNotFoundException?

Laurent
quelle
IMO das ist die wahre Antwort. +1
LC
Nicht wirklich, weil: Bietet eine Ausnahme für SettingsProperty-Objekte, die nicht gefunden werden. Was kommt von: Wird intern als Klasse verwendet, die Metadaten zu einer einzelnen Konfigurationseigenschaft darstellt. Dies ist nicht dasselbe wie ein fehlender Konfigurationswert.
Karol Haliński
7

ConfigurationErrorsExceptionist die richtige Ausnahme für die von Ihnen beschriebene Situation. Eine frühere Version der MSDN-Dokumentation für ConfigurationErrorsExceptionist sinnvoller.

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

Die frühere MSDN-Zusammenfassung und Anmerkungen sind:

  • Die Ausnahme, die ausgelöst wird, wenn ein Konfigurationssystemfehler aufgetreten ist.
  • Die ConfigurationErrorsException Ausnahme wird ausgelöst, wenn beim Lesen oder Schreiben von Konfigurationsinformationen ein Fehler auftritt.
Daniel Richardson
quelle
7
Aus der Dokumentation: "Diese API unterstützt die Produktinfrastruktur und ist nicht für die direkte Verwendung in Code vorgesehen. Initialisiert eine neue Instanz der ConfigurationErrorsException-Klasse."
Oleg Sh
6

Die ConfigurationElement-Klasse (die Basisklasse vieler konfigurationsbezogener Klassen wie ConfigurationSection) verfügt über eine Methode namens OnRequiredPropertyNotFound (es gibt auch andere Hilfsmethoden). Sie können diese vielleicht anrufen.

Die OnRequiredPropertyNotFound wird folgendermaßen implementiert:

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)); }
Gaspar Nagy
quelle
1

Ich würde es aufsaugen und mein eigenes rollen ... aber bevor Sie das tun, ist es möglich, dass das System einen Standardwert für diese Konfigurationseinstellung annimmt? Ich versuche im Allgemeinen, dies für jede Einstellung zu tun, die möglicherweise von Ops Management-Leuten übersehen wird ... (oder vielleicht sollte ich für so viele Einstellungen wie möglich sagen - für einige ist es eindeutig nicht angemessen, dass das System eine Standardentscheidung trifft. ..)

Im Allgemeinen ist eine benutzerdefinierte Ausnahme kein großer Aufwand ... hier ein Beispiel ...

[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
}
Charles Bretana
quelle
2
MSDN: ... eine Anwendung, die ihre eigenen Ausnahmen erstellen muss, [...] um benutzerdefinierte Ausnahmen von der Exception-Klasse abzuleiten. Es wurde ursprünglich angenommen, dass benutzerdefinierte Ausnahmen von der ApplicationException-Klasse abgeleitet werden sollten. In der Praxis wurde jedoch kein signifikanter Mehrwert festgestellt.
Gaspar Nagy
Ja, ich denke, das lag daran, dass die MS-Programmierer, die das Framework codiert haben, zahlreiche CLR-Ausnahmen von ApplicationException abgeleitet haben, wodurch die Bedeutung der Unterscheidung zerstört wurde. Ich mache es trotzdem, da ich keinen Schaden darin sehe ...
Charles Bretana
1

Eine alternative Methode, die Sie für Ihre Konfigurationsdateien verwenden könnten, wäre die Verwendung von benutzerdefinierten Konfigurationsabschnitten im Gegensatz zu AppSettings. Auf diese Weise können Sie festlegen, dass eine Eigenschaft IsRequiredund das Konfigurationssystem diese Prüfung für Sie übernehmen. Wenn die Eigenschaft fehlt, wird ein ConfigurationErrorsExceptionausgelöst, was vermutlich die Antwort unterstützt, dass Sie diese Ausnahme in Ihrem Fall verwenden sollten.

Jogh
quelle
0

Meine allgemeine Regel wäre:

  1. Wenn der Fall der fehlenden Konfiguration nicht sehr häufig ist und ich glaube, dass ich diesen Fall niemals anders als andere Ausnahmen behandeln möchte, verwende ich einfach die grundlegende Klasse "Exception" mit einer entsprechenden Meldung:

    neue Ausnahme auslösen ("meine Nachricht hier")

  2. Wenn ich möchte oder denke, dass es eine hohe Wahrscheinlichkeit gibt, dass ich diesen Fall anders als die meisten anderen Ausnahmen behandeln möchte, würde ich meinen eigenen Typ rollen, wie die Leute hier bereits vorgeschlagen haben.

Hershi
quelle
0

Ich stimme der Prämisse Ihrer Frage eher nicht zu:

Kurz gesagt, ich benötige eine Standardausnahme, die ausgelöst werden sollte, wenn eine Anwendungskonfigurationseinstellung fehlt oder einen ungültigen Wert enthält. Sie würden denken, dass das Framework eine solche Ausnahme für Anwendungen enthält. (Anscheinend, aber es wurde als veraltet markiert und durch etwas viel Größeres ersetzt.)

Laut der MSDN-Dokumentation zu System.Exception ( Ausnahmeklasse sollten Sie aus Leistungsgründen (auf die andere bei Stack Overflow und anderswo hingewiesen haben) keine Ausnahmen für Benutzereingabefehler auslösen . Dies scheint sinnvoll zu sein Nun - warum kann Ihre Funktion nicht false zurückgeben, wenn die Benutzereingabe falsch eingegeben wurde und die Anwendung dann ordnungsgemäß beendet wird? Dies scheint eher ein Designproblem als ein Problem zu sein, mit dem eine Ausnahme ausgelöst werden soll.

Wie andere bereits betont haben , gibt es keinen Grund, warum Sie Ihren Ausnahmetyp nicht durch Erben von System.Exception definieren können , wenn Sie wirklich eine Ausnahme auslösen müssen - aus welchem ​​Grund auch immer.

Matt Jordan
quelle
2
Warum genau sollte die Leistung in diesem speziellen Szenario von Bedeutung sein? IUC, dann wird die Ausnahme genau einmal ausgelöst und der Prozess wird wahrscheinlich trotzdem danach abgebrochen (natürlich nachdem dem Benutzer ein nettes Popup angezeigt wurde). (Fortsetzung
2
Das Zurückgeben eines Fehlercodes anstelle des Auslösens einer Ausnahme kann schmerzhaft sein, da Sie die Fehlerinformationen dann selbst auf dem Aufrufstapel weitergeben müssten. Sie sollten Ausnahmen für relativ seltene Fehler verwenden, die möglicherweise über mehrere Stapelrahmen übertragen werden. Beides gilt hier.
1
Sie haben etwas verpasst: "Wenn eine Anwendungskonfigurationseinstellung fehlt oder einen ungültigen Wert enthält", ist dies nicht dasselbe wie eine falsche Benutzereingabe. Dies ist eine grundlegende Konfiguration, die fehlt. Sollte eine benutzerdefinierte Ausnahme sein und die Ausführung der App stoppen.
JCollum
2
In dieser speziellen Anwendung wird es fast ausschließlich von den Einstellungen in der Konfigurationsdatei bestimmt. Wenn die Einstellungen nicht darin enthalten sind (wo sie verschlüsselt sind), kann die Anwendung nicht fortgesetzt werden und muss beendet werden. Eine Ausnahme ist praktisch erforderlich.
Mike Hofer
1
Dies kann sicherlich zu einer Semantik führen, und die Struktur Ihres Codes bestimmt offensichtlich die beste Implementierung für Ihre Situation. Wenn Sie jedoch freie Hand im Design hätten, würde ich immer noch mit einem Objekt den Fehler protokollieren und eine Ausnahme ordnungsgemäß beenden, wobei die Leistung ein Problem darstellt oder nicht.
Matt Jordan
-2

Sie können versuchen, die XML-Ausnahme zu erben oder sie einfach zu verwenden.

StingyJack
quelle