.NET: który wyjątek zgłosić, gdy brakuje wymaganego ustawienia konfiguracji?

123

Oto standardowy scenariusz:

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

Problem w tym, że nie jestem do końca pewien, który wyjątek SomeStandardExceptionpowinien być.

Przejrzałem 3.5 Framework i znalazłem dwóch prawdopodobnych kandydatów: ConfigurationExceptioni ConfigurationErrorsException.

System.Configuration.ConfigurationException

Wyjątek, który jest generowany, gdy wystąpił błąd systemu konfiguracji.

Uwagi

ConfigurationExceptionJest wyjątek, gdy aplikacja próbuje odczytać dane lub zapisu pliku konfiguracyjnego, ale nie powiodło się. Niektóre możliwe przyczyny mogą obejmować nieprawidłowy format XML w pliku konfiguracyjnym, problemy z uprawnieniami do plików i właściwości konfiguracyjne z nieprawidłowymi wartościami.

Uwaga:

ConfigurationExceptionPrzedmiot jest utrzymywany przez kompatybilności wstecznej. ConfigurationErrorsException Przedmiot zastępuje go do konfiguracji systemu.

Ten wyjątek faktycznie brzmi idealnie dla tego, czego potrzebuję, ale został oznaczony jako przestarzały, więc ixnay on atthay.

To prowadzi nas do całkowicie zagadkowego ConfigurationErrorsException:

System.Configuration.ConfigurationErrorsException

Bieżąca wartość nie jest jedną z wartości EnableSessionState.

Jak widać, jego dokumentacja jest całkowicie bezużyteczna. (Tak jest zarówno w pomocy lokalnej, jak i online). Analiza samej klasy pokazuje, że jest to drastyczna przesada, jeśli chodzi o to, czego chcę.

Krótko mówiąc, potrzebuję standardowego wyjątku, który powinien zostać wyrzucony, gdy brakuje ustawienia konfiguracji aplikacji lub zawiera nieprawidłową wartość. Można by pomyśleć, że Framework zawiera taki wyjątek, aby można było z niego korzystać. (Najwyraźniej tak, ale oznaczono go jako przestarzały i zastąpiono go czymś o wiele większym zakresie.)

Jakie rozwiązania, jeśli w ogóle, używacie do tego i czy będę musiał to wciągnąć i rzucić własny wyjątek?

Edytuj dodatki

Niektórzy pytali, czy mogę podać wartość domyślną, i kontynuują. W niektórych przypadkach tak, iw takich przypadkach wyjątek nie zostałby zgłoszony. Jednak w przypadku niektórych ustawień nie będzie to miało zastosowania. Na przykład: nazwy i poświadczenia serwera bazy danych, serwery uwierzytelniające i ścieżki do zainstalowanych aplikacji innych firm.

Warto również zauważyć, że aplikacja, nad którą głównie pracuję, jest aplikacją konsolową działającą w trybie wsadowym i chcę, aby rzucała wyjątek, który jest przechwytywany przez główną metodę i odpowiednio rejestrowany, jeśli coś nie jest odpowiednio skonfigurowane. (Jest to starszy kod, który odziedziczyłem i obecnie po prostu zakłada, że wszystko jest brzoskwiniowe).

Mike Hofer
źródło
1
Dokumentacja dla System.Configuration.ConfigurationErrorsException została zaktualizowana.
slolife

Odpowiedzi:

36

Nie jesteś ograniczony w zgłaszaniu wyjątków do istniejących wyjątków w Framework. Jeśli zdecydujesz się skorzystać z istniejących wyjątków, nie musisz bezwzględnie przestrzegać dokumentacji co do joty. Dokumentacja opisuje, w jaki sposób framework używa danego wyjątku, ale nie oznacza żadnych ograniczeń co do tego , jak zdecydujesz się użyć / ponownie użyć istniejącego wyjątku.

To Twoja aplikacja - o ile ją udokumentujesz i wyraźnie wskażesz wyjątek, który zostanie wyrzucony w konkretnym przypadku braku wartości konfiguracyjnej, możesz użyć dowolnego wyjątku, który Ci się podoba. Jeśli chcesz uzyskać bardzo szczegółowe wskazanie brakującej wartości, możesz rozważyć napisanie własnego wyjątku ConfigurationSettingMissing:

[Serializable]
public class ConfigurationMissingException : ConfigurationErrorsException
{}

EDYCJA: Pisanie własnego wyjątku w tym przypadku niesie ze sobą dodatkową korzyść w postaci zagwarantowania, że ​​nigdy nie będzie nieporozumień co do tego, skąd pochodzi wyjątek - frameworka lub aplikacja. Framework nigdy nie wyrzuci niestandardowych wyjątków.

UPDATE: Zgadzam się z komentarzami, więc zmieniłem podklasę na ConfigurationErrorsException z Exception. Myślę, że ogólnie dobrym pomysłem jest tworzenie podklasy niestandardowych wyjątków od istniejących wyjątków Framework, jeśli to możliwe, unikając klasy Exception, chyba że potrzebujesz wyjątku specyficznego dla aplikacji.

Dave Swersky
źródło
17
Raczej się nie zgadzam. Jeśli masz zamiar użyć istniejącego wyjątku, powinien być używany DOKŁADNIE tak, jak mówi dokumentacja, że ​​został użyty, w przeciwnym razie zmylisz tych, którzy przyjdą po ciebie. Jeśli zamierzasz zrobić coś innego, po prostu utwórz własny wyjątek, tak jak powiedziałeś.
Robert C. Barth
1
Nie zgadzam się. O ile nie masz scenariusza przechwytywania niestandardowego wyjątku, co jest mało prawdopodobne w przypadku błędu konfiguracji, lepiej jest ponownie użyć istniejącego Type (ConfigurationErrorsException). A jeśli utworzysz typ niestandardowy, wyprowadzę go z powiązanego typu, takiego jak ConfigurationErrorsException.
Joe,
@Robert & Joe - Nie sugeruję, aby istniejące wyjątki Framework były używane niezgodnie z ich zamierzoną funkcją, tylko że istnieje pewna elastyczność, o ile konkretny przypadek (brakująca wartość) pasuje do przypadku ogólnego (ConfigurationErrorsException).
Dave Swersky
1
Mogą wystąpić problemy z tym, jeśli wyrzucasz wyjątek w aplikacji ASP.NET, ponieważ ConfigurationErrorsException i klasy pochodne od niego nie są przechwytywane w chronionej metodzie OnError lub przez zdarzenie Global ASAX Error. Zobacz to pytanie, które opublikowałem .... stackoverflow.com/questions/25299325/…
Mick
48

Osobiście użyłbym InvalidOperationException , ponieważ jest to problem ze stanem obiektu, a nie systemem konfiguracji. W końcu nie powinieneś pozwolić, aby te ustawienia były konfigurowane przez kod, a nie przez konfigurację? Ważną częścią tutaj nie jest to, że w pliku app.config nie było linii, ale że brakowało wymaganej informacji.

Dla mnie ConfigurationException (i jego zamiennik, ConfigurationErrorsException - pomimo wprowadzającej w błąd dokumentacji MSDN) są dla błędów w zapisywaniu, odczytywaniu itp. Konfiguracji.

Mark Brackett
źródło
Zdecydowałem się na InvalidOperationException, ponieważ jest obsługiwany przez metodę OnError chronioną przez stronę ASP.NET, podczas gdy ConfigurationErrorsException i wszystkie wyprowadzone z niego wyjątki nie są
Mick
2
To by mnie naprawdę zaskoczyło, jeśli otrzymam InvalidOperationException, jeśli źle otrzymam konfigurację.
keuleJ
18

Jak powiedział Daniel Richardson, ConfigurationErrorsException to ten, którego należy użyć. Ogólnie zaleca się tworzenie własnych niestandardowych typów wyjątków tylko wtedy, gdy masz scenariusz ich obsługi. W przypadku błędów konfiguracji, które zwykle są krytyczne, rzadko się to zdarza, dlatego zwykle bardziej odpowiednie jest ponowne użycie istniejącego typu ConfigurationErrorsException.

Przed .NET 2.0 zalecano używanie System.Configuration.ConfigurationException . ConfigurationException stał się przestarzały w .NET 2.0 z powodów, które nigdy nie były dla mnie jasne, a zalecenie zostało zmienione na użycie ConfigurationErrorsException.

Używam metody pomocniczej, aby zgłosić wyjątek, aby łatwo zmienić wyjątek rzucany w jednym miejscu podczas migracji z .NET 1.x do 2.0 lub jeśli Microsoft zdecyduje się ponownie zmienić zalecenie:

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
źródło
16

O co chodzi System.Configuration.SettingsPropertyNotFoundException?

Laurent
źródło
IMO to jest prawdziwa odpowiedź. +1
LC
Niezupełnie, ponieważ: zapewnia wyjątek dla obiektów SettingsProperty, które nie zostały znalezione. Pochodzi z: Używany wewnętrznie jako klasa reprezentująca metadane dotyczące indywidualnej właściwości konfiguracji. Co nie jest tym samym, co brakująca wartość konfiguracji.
Karol Haliński
7

ConfigurationErrorsExceptionto właściwy wyjątek do rzucenia w opisanej sytuacji. Wcześniejsza wersja dokumentacji MSDN dla ConfigurationErrorsExceptionma większy sens.

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

Wcześniejsze podsumowanie i uwagi MSDN to:

  • Wyjątek, który jest generowany, gdy wystąpił błąd systemu konfiguracji.
  • ConfigurationErrorsException Jest wyjątek, gdy wystąpi błąd podczas informacje konfiguracyjne są odczytywane lub zapisywane.
Daniel Richardson
źródło
7
z dokumentacji: „Ten interfejs API obsługuje infrastrukturę produktu i nie jest przeznaczony do użycia bezpośrednio w kodzie. Inicjuje nowe wystąpienie klasy ConfigurationErrorsException.”
Oleg Sh
6

Klasa ConfigurationElement (która jest klasą bazową wielu klas związanych z konfiguracją, takich jak ConfigurationSection) ma metodę o nazwie OnRequiredPropertyNotFound (są też inne metody pomocnicze). Możesz do nich zadzwonić.

OnRequiredPropertyNotFound jest zaimplementowany w następujący sposób:

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
źródło
1

Wyssałbym to i skręciłbym własne ... ale zanim to zrobisz, czy możliwe jest, aby system przyjął domyślną wartość tego ustawienia konfiguracyjnego? Generalnie staram się to robić dla każdego ustawienia, które może zostać pominięte przez osoby zarządzające operacjami ... (a może powinienem powiedzieć, dla jak największej liczby ustawień - dla niektórych najwyraźniej nie jest właściwe, aby system podejmował domyślną decyzję. ..)

ogólnie rzecz biorąc niestandardowy wyjątek nie wymaga dużego wysiłku ... oto przykład ...

[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
źródło
2
MSDN: ... aplikacja, która musi tworzyć własne wyjątki, [...] wyprowadzać niestandardowe wyjątki z klasy Exception. Początkowo sądzono, że wyjątki niestandardowe powinny pochodzić z klasy ApplicationException; jednakże w praktyce nie stwierdzono, aby dodało to znaczącej wartości.
Gaspar Nagy,
Tak, myślę, że to dlatego, że programiści MS, którzy kodowali framework, wyprowadzili liczne wyjątki CLR z ApplicationException, niszcząc w ten sposób znaczenie tego rozróżnienia. Mimo to nadal to robię, ponieważ nie widzę w tym żadnej krzywdy ...
Charles Bretana
1

Alternatywną metodą, której możesz użyć dla swoich plików konfiguracyjnych, byłoby użycie niestandardowych sekcji konfiguracyjnych w przeciwieństwie do AppSettings. W ten sposób możesz określić, że właściwość IsRequiredi system konfiguracyjny zajmą się tym sprawdzaniem za Ciebie. Jeśli brakuje tej właściwości, wyrzuci ona, ConfigurationErrorsExceptionwięc przypuszczam, że to potwierdza odpowiedź, że powinieneś użyć tego wyjątku w swoim przypadku.

Yogh
źródło
0

Moja ogólna zasada brzmi:

  1. Jeśli przypadek brakującej konfiguracji nie jest zbyt powszechny i ​​uważam, że nigdy nie chciałbym załatwić tego przypadku inaczej niż inne wyjątki, po prostu używam podstawowej klasy "Exception" z odpowiednim komunikatem:

    zgłoś nowy wyjątek („moja wiadomość”)

  2. Gdybym chciał lub wydaje mi się, że istnieje duże prawdopodobieństwo, że chciałbym zająć się tym przypadkiem w inny sposób niż większość innych wyjątków, wyrzuciłbym swój własny typ, jak już sugerowali tutaj ludzie.

Hershi
źródło
0

Nie zgadzam się z przesłanką twojego pytania:

Krótko mówiąc, potrzebuję standardowego wyjątku, który powinien zostać wyrzucony, gdy brakuje ustawienia konfiguracji aplikacji lub zawiera nieprawidłową wartość. Można by pomyśleć, że Framework zawiera taki wyjątek, aby można było z niego korzystać. (Najwyraźniej tak, ale oznaczono go jako przestarzały i zastąpiono go czymś o wiele większym zakresie.)

Zgodnie z dokumentacją MSDN na System.Exception ( klasa wyjątków , naprawdę nie powinieneś rzucać wyjątków dla błędów wprowadzania danych przez użytkownika, ze względu na wydajność (co zostało wskazane przez innych na Stack Overflow i gdzie indziej). cóż - dlaczego funkcja nie może zwrócić wartości false, jeśli dane wejściowe użytkownika zostały wprowadzone niepoprawnie, a następnie aplikacja została bezpiecznie zamknięta? Wydaje się, że jest to bardziej problem projektowy niż problem, z którym należy zgłosić wyjątek.

Jak zauważyli inni, jeśli naprawdę musisz zgłosić wyjątek - z jakiegokolwiek powodu - nie ma żadnego powodu, dla którego nie mógłbyś zdefiniować swojego typu wyjątku poprzez dziedziczenie po System.Exception.

Matt Jordan
źródło
2
Dlaczego dokładnie wydajność miałaby mieć znaczenie w tym konkretnym scenariuszu? IUC, wtedy wyjątek jest generowany dokładnie raz, a proces prawdopodobnie i tak się kończy (oczywiście po wyświetleniu użytkownikowi ładnego wyskakującego okienka). (ciąg dalszy ...)
2
Zwracanie kodu błędu zamiast zgłaszania wyjątku może być bolesne, ponieważ wtedy trzeba byłoby samodzielnie propagować informacje o błędzie w stosie wywołań. Należy używać wyjątków dla stosunkowo rzadkich błędów, które mogą być propagowane w kilku ramkach stosu. Oba mają tutaj zastosowanie.
1
Coś przeoczyłeś: „gdy brakuje ustawienia konfiguracji aplikacji lub zawiera nieprawidłową wartość”, to nie to samo, co złe dane wprowadzone przez użytkownika. Brakuje podstawowej konfiguracji. Powinien być niestandardowym wyjątkiem i powinien zatrzymać uruchamianie aplikacji.
jcollum
2
W tej konkretnej aplikacji prawie całkowicie zależy to od ustawień w pliku konfiguracyjnym. Jeśli ustawień nie ma w nim (gdzie są zaszyfrowane), aplikacja nie może kontynuować i musi się zakończyć. Wyjątek jest praktycznie wymagany.
Mike Hofer
1
To z pewnością może dostać się do semantyki, a struktura twojego kodu będzie oczywiście dyktować najlepszą implementację dla twojej sytuacji. Mimo to, gdybyś miał swobodne panowanie w projekcie, nadal korzystałbym z obiektu, aby zarejestrować błąd i wdzięczne wyjście z wyjątku, niezależnie od tego, czy problemem jest wydajność, czy nie.
Matt Jordan
-2

Możesz spróbować odziedziczyć wyjątek XML lub po prostu go użyć.

StingyJack
źródło