.NET: Quelle exception à lever lorsqu'un paramètre de configuration requis est manquant?

123

Voici un scénario standard:

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

Le problème est que je ne suis pas tout à fait sûr de savoir quelle exception SomeStandardExceptiondevrait être.

J'ai parcouru le cadre 3.5 et j'ai trouvé deux candidats probables: ConfigurationExceptionet ConfigurationErrorsException.

System.Configuration.ConfigurationException

L'exception qui est levée lorsqu'une erreur du système de configuration s'est produite.

Remarques

L' ConfigurationExceptionexception est levée si l'application tente de lire ou d'écrire des données dans le fichier de configuration mais échoue. Certaines raisons possibles à cela peuvent inclure un XML malformé dans le fichier de configuration, des problèmes d'autorisation de fichier et des propriétés de configuration avec des valeurs non valides.

Remarque:

L' ConfigurationExceptionobjet est conservé à des fins de compatibilité descendante. L' ConfigurationErrorsException objet le remplace pour le système de configuration.

Cette exception semble en fait parfaite pour ce dont j'ai besoin, mais elle a été marquée comme obsolète, donc, ixnay sur atthay.

Cela nous amène au tout à fait déroutant ConfigurationErrorsException:

System.Configuration.ConfigurationErrorsException

La valeur actuelle ne fait pas partie des valeurs EnableSessionState.

Comme vous pouvez le voir, sa documentation est totalement inutile. (C'est comme ça dans l'aide locale et en ligne.) Un examen de la classe elle-même montre que c'est excessivement excessif pour ce que je veux.

En un mot, j'ai besoin d'une exception standard qui doit être levée lorsqu'un paramètre de configuration d'application est manquant ou contient une valeur non valide. On pourrait penser que le Framework contenait une telle exception pour les applications à utiliser. (C'est apparemment le cas, mais il a été marqué comme obsolète et a été remplacé par quelque chose de beaucoup plus large.)

Quelles solutions, le cas échéant, utilisez-vous pour cela, et vais-je devoir les aspirer et lever ma propre exception pour cela?

Modifier les addenda

Certains ont demandé si je pouvais ou non fournir une valeur par défaut et continuer. Dans certains cas, oui, et dans ces cas, l'exception ne serait pas levée. Cependant, pour certains paramètres, cela ne s'appliquera pas. Par exemple: noms et informations d'identification du serveur de base de données, serveurs d'authentification et chemins d'accès aux applications tierces installées.

Il convient également de noter que l'application sur laquelle je travaille principalement est une application console s'exécutant en mode batch, et je veux qu'elle lève une exception qui est interceptée par la méthode principale et enregistrée de manière appropriée si la chose n'est pas correctement configurée. (C'est du code hérité que j'ai hérité, et suppose actuellement que tout est parfait.)

Mike Hofer
la source
1
La documentation pour System.Configuration.ConfigurationErrorsException a été mise à jour.
slolife

Réponses:

36

Vous n'êtes pas limité dans votre levée d'exceptions aux exceptions existantes dans le Framework. Si vous décidez d'utiliser des exceptions existantes, vous n'êtes pas obligé de suivre la documentation à la lettre. La documentation décrira comment le framework utilise une exception donnée, mais n'implique aucune limitation sur la façon dont vous choisissez d'utiliser / réutiliser une exception existante.

C'est votre application - tant que vous la documentez et que vous indiquez clairement l'exception qui sera levée dans le cas spécifique d'une valeur de configuration manquante, vous pouvez utiliser toute exception que vous aimez. Si vous voulez une indication très spécifique d'une valeur manquante , vous pouvez envisager d'écrire votre propre exception ConfigurationSettingMissing:

[Serializable]
public class ConfigurationMissingException : ConfigurationErrorsException
{}

EDIT: écrire votre propre exception dans ce cas présente l'avantage supplémentaire de garantir qu'il n'y aura jamais de confusion quant à l'origine de l'exception - le framework ou votre application. Le framework ne lèvera jamais vos exceptions personnalisées.

MISE À JOUR: Je suis d'accord avec les commentaires, j'ai donc changé la sous-classe en ConfigurationErrorsException depuis Exception. Je pense que c'est généralement une bonne idée de sous-classer les exceptions personnalisées des exceptions Framework existantes lorsque cela est possible, en évitant la classe Exception sauf si vous avez besoin d'une exception spécifique à l'application.

Dave Swersky
la source
17
Je suis quelque peu en désaccord. Si vous allez utiliser une exception existante, elle doit être utilisée EXACTEMENT comme la documentation dit qu'elle est utilisée, sinon vous allez confondre ceux qui viennent après vous. Si vous voulez faire quelque chose de différent, créez simplement votre propre exception, comme vous l'avez dit.
Robert C. Barth
1
Je ne suis pas d'accord. Sauf si vous disposez d'un scénario pour intercepter votre exception personnalisée, peu probable dans le cas d'une erreur de configuration, il est préférable de réutiliser un type existant (ConfigurationErrorsException). Et si vous créez un type personnalisé, je le dériverais d'un type associé tel que ConfigurationErrorsException.
Joe le
@Robert & Joe- Je ne suggère pas que les exceptions de Framework existantes doivent être utilisées de manière incohérente avec leur fonction prévue, mais simplement qu'il y a une certaine flexibilité tant que le cas spécifique (valeur manquante) correspond au cas général (ConfigurationErrorsException).
Dave Swersky
1
Il peut y avoir des problèmes avec cela si vous lancez l'exception dans une application ASP.NET en tant que ConfigurationErrorsException et que les classes qui en dérivent ne sont pas interceptées dans la méthode OnError protégée ou par l'événement Global ASAX Error. Voir cette question que j'ai postée .... stackoverflow.com/questions/25299325/…
Mick
48

Personnellement, j'utiliserais InvalidOperationException , car c'est un problème avec l'état de l'objet - pas le système de configuration. Après tout, ne devriez-vous pas autoriser ces paramètres à être définis par code et non par configuration? L'important ici n'est pas qu'il n'y avait pas de ligne dans app.config, mais qu'une information requise n'était pas présente.

Pour moi, ConfigurationException (et son remplacement, ConfigurationErrorsException - malgré les documents MSDN trompeurs) sont des erreurs de sauvegarde, de lecture, etc. de la configuration.

Mark Brackett
la source
J'ai opté pour InvalidOperationException, car il est géré par la méthode OnError protégée par page ASP.NET, tandis que ConfigurationErrorsException et toutes les exceptions qui en découlent ne le sont pas
Mick
2
Cela me surprendrait vraiment si j'obtiens une exception InvalidOperationException si la configuration est erronée.
keuleJ
18

Comme l'a dit Daniel Richardson, ConfigurationErrorsException est celui à utiliser. En général, il est recommandé de créer vos propres types d'exceptions personnalisés uniquement si vous disposez d'un scénario pour les gérer. Dans le cas d'erreurs de configuration, qui sont généralement fatales, c'est rarement le cas, il est donc généralement plus approprié de réutiliser le type ConfigurationErrorsException existant.

Avant .NET 2.0, la recommandation était d'utiliser System.Configuration.ConfigurationException . ConfigurationException est devenu obsolète dans .NET 2.0, pour des raisons qui n'étaient jamais claires pour moi, et la recommandation a changé pour utiliser ConfigurationErrorsException.

J'utilise une méthode d'assistance pour lever l'exception afin qu'il soit facile de modifier l'exception levée au même endroit lors de la migration de .NET 1.x vers 2.0, ou si Microsoft décide de modifier à nouveau la recommandation:

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
la source
16

Et quoi System.Configuration.SettingsPropertyNotFoundException?

Laurent
la source
IMO c'est la vraie réponse. +1
LC
Pas vraiment, car: Fournit une exception pour les objets SettingsProperty qui ne sont pas trouvés. Qui vient de: Utilisé en interne comme classe qui représente les métadonnées sur une propriété de configuration individuelle. Ce qui n'est pas la même chose qu'une valeur manquante de configuration.
Karol Haliński
7

ConfigurationErrorsExceptionest la bonne exception à lancer dans la situation que vous décrivez. Une version antérieure de la documentation MSDN pour ConfigurationErrorsExceptionest plus logique.

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

Le résumé et les remarques MSDN précédents sont:

  • L'exception qui est levée lorsqu'une erreur du système de configuration s'est produite.
  • L' ConfigurationErrorsException exception est levée lorsqu'une erreur se produit pendant la lecture ou l'écriture des informations de configuration.
Daniel Richardson
la source
7
à partir de la documentation: "Cette API prend en charge l'infrastructure du produit et n'est pas destinée à être utilisée directement à partir de votre code. Initialise une nouvelle instance de la classe ConfigurationErrorsException."
Oleg Sh
6

La classe ConfigurationElement (qui est la classe de base de nombreuses classes liées à la configuration, comme ConfigurationSection) a une méthode appelée OnRequiredPropertyNotFound (il existe également d'autres méthodes d'assistance). Vous pouvez peut-être les appeler.

OnRequiredPropertyNotFound est implémenté comme ceci:

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
la source
1

Je le sucerais et roulerais le mien ... mais avant cela, est-il possible que le système prenne une valeur par défaut pour ce paramètre de configuration? J'essaie généralement de le faire pour chaque paramètre qui pourrait manquer aux gens de la gestion des opérations ... (ou peut-être devrais-je dire, pour autant de paramètres que possible - pour certains, il n'est clairement pas approprié que le système prenne une décision par défaut. ..)

en général, une exception personnalisée ne demande pas beaucoup d'efforts ... voici un exemple ...

[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
la source
2
MSDN: ... une application qui doit créer ses propres exceptions, [...] dériver des exceptions personnalisées de la classe Exception. On pensait à l'origine que les exceptions personnalisées devraient dériver de la classe ApplicationException; cependant, dans la pratique, cela n'a pas été trouvé pour ajouter une valeur significative.
Gaspar Nagy
Oui, je pense que c'est parce que les programmeurs MS qui ont codé le framework ont ​​dérivé de nombreuses exceptions CLR d'ApplicationException, détruisant ainsi la signification de la distinction ... Je le fais toujours, car je n'y vois aucun mal ...
Charles Bretana
1

Une autre méthode que vous pourriez utiliser pour vos fichiers de configuration serait d'utiliser des sections de configuration personnalisées par opposition à AppSettings. De cette façon, vous pouvez spécifier qu'une propriété IsRequiredet le système de configuration gèrent cette vérification à votre place. Si la propriété est manquante, elle lancera un ConfigurationErrorsExceptiondonc je suppose que cela prend en charge la réponse que vous devez utiliser cette exception dans votre cas.

Yogh
la source
0

Ma règle générale serait:

  1. Si le cas de la configuration manquante n'est pas très courant et que je pense que je ne voudrais jamais gérer ce cas différemment des autres exceptions, j'utilise simplement la classe de base "Exception" avec un message approprié:

    lancer une nouvelle exception ("mon message ici")

  2. Si je veux ou pense qu'il y a une forte probabilité que je veuille traiter ce cas d'une manière différente de la plupart des autres exceptions, je lancerais mon propre type comme les gens l'ont déjà suggéré ici.

Hershi
la source
0

J'ai tendance à ne pas être d'accord avec la prémisse de votre question:

En un mot, j'ai besoin d'une exception standard qui doit être levée lorsqu'un paramètre de configuration d'application est manquant ou contient une valeur non valide. On pourrait penser que le Framework contenait une telle exception pour les applications à utiliser. (C'est apparemment le cas, mais il a été marqué comme obsolète et a été remplacé par quelque chose de beaucoup plus large.)

Selon la documentation MSDN sur System.Exception ( Exception Class , vous ne devriez vraiment pas lancer d'exceptions pour les erreurs de saisie utilisateur, pour des raisons de performances (qui ont été signalées par d'autres sur Stack Overflow et ailleurs). Cela semble logique car Eh bien - pourquoi votre fonction ne peut-elle pas retourner false si l'entrée de l'utilisateur est mal saisie, puis que l'application se ferme correctement? Cela semble être plus un problème de conception qu'un problème avec l'exception à lever.

Comme d' autres l' ont souligné, si vous vraiment avez à jeter une exception - pour une raison quelconque - il n'y a aucune raison pour laquelle vous ne pouvez définir votre type d'exception en héritant de System.Exception.

Matt Jordan
la source
2
Pourquoi exactement les performances importent-elles dans ce scénario spécifique? IUC, alors l'exception est lancée exactement une fois et le processus s'arrête probablement par la suite de toute façon (bien sûr, après avoir montré une belle fenêtre contextuelle à l'utilisateur). (à suivre ...)
2
Renvoyer un code d'erreur au lieu de lancer une exception peut être douloureux, car vous devrez ensuite propager vous-même les informations d'erreur dans la pile d'appels. Vous devez utiliser des exceptions pour les erreurs relativement rares qui peuvent se propager sur plusieurs cadres de pile. Les deux s'appliquent ici.
1
Vous avez manqué quelque chose: "lorsqu'un paramètre de configuration d'application est manquant ou contient une valeur non valide", ce n'est pas la même chose qu'une mauvaise entrée utilisateur. Il s'agit d'une configuration de base qui manque. Doit être une exception personnalisée et doit empêcher l'application de s'exécuter.
jcollum
2
Dans cette application particulière, il est presque entièrement régi par les paramètres du fichier de configuration. Si les paramètres ne s'y trouvent pas (là où ils sont chiffrés), l'application ne peut pas continuer et doit s'arrêter. Une exception est pratiquement requise.
Mike Hofer
1
Cela peut certainement entrer dans la sémantique, et la structure de votre code dictera évidemment la meilleure implémentation pour votre situation. Pourtant, si vous aviez le libre arbitre dans la conception, j'irais toujours avec un objet pour consigner l'erreur et une sortie gracieuse sur une exception, les performances étant un problème ou non.
Matt Jordan
-2

Vous pouvez essayer d'hériter de l'exception XML ou simplement de l'utiliser.

StingyJack
la source