.NET: какое исключение создавать при отсутствии обязательного параметра конфигурации?

123

Вот стандартный сценарий:

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

Проблема в том, что я не совсем уверен, какое исключение SomeStandardExceptionдолжно быть.

Я просмотрел 3.5 Framework и нашел двух вероятных кандидатов: ConfigurationExceptionи ConfigurationErrorsException.

System.Configuration.ConfigurationException

Исключение, которое выдается при возникновении системной ошибки конфигурации.

замечания

ConfigurationExceptionИсключение , если приложение пытается считывать или записывать данные в файл конфигурации , но безуспешно. Некоторые возможные причины этого могут включать в себя искаженный XML в файле конфигурации, проблемы с правами доступа к файлам и свойства конфигурации с недопустимыми значениями.

Примечание:

ConfigurationExceptionОбъект поддерживается для обратной совместимости. ConfigurationErrorsException Объект заменяет его для конфигурации системы.

Это исключение на самом деле звучит идеально для того, что мне нужно, но оно было помечено как устаревшее, поэтому ixnay on atthay.

Это подводит нас к совершенно загадочному вопросу ConfigurationErrorsException:

System.Configuration.ConfigurationErrorsException

Текущее значение не является одним из значений EnableSessionState.

Как видите, его документация совершенно бесполезна. (Так обстоит дело как в локальной, так и в онлайн-справке.) Изучение самого класса показывает, что это решительный перебор для того, что я хочу.

Короче говоря, мне нужно стандартное исключение, которое должно выдаваться, когда параметр конфигурации приложения отсутствует или содержит недопустимое значение. Можно подумать, что в Framework есть такое исключение, которое можно использовать в приложениях. (По-видимому, это было так, но оно было помечено как устаревшее и было заменено чем-то гораздо более масштабным.)

Какие решения, если таковые имеются, вы, ребята, используете для этого, и мне придется принять это и свернуть собственное исключение для этого?

Изменить дополнение

Некоторые спрашивали, могу ли я указать значение по умолчанию, и продолжали. В некоторых случаях да, и в этих случаях исключение не будет создано. Однако для некоторых настроек это не применимо. Например: имена и учетные данные серверов базы данных, серверы аутентификации и пути к установленным сторонним приложениям.

Также стоит отметить, что приложение, над которым я в основном работаю, является консольным приложением, работающим в пакетном режиме, и я хочу, чтобы оно генерировало исключение, которое было перехвачено основным методом и зарегистрировано соответствующим образом, если это не настроено должным образом. (Это старый код, который я унаследовал, и в настоящее время он предполагает, что все безупречно.)

Майк Хофер
источник
1
System.Configuration.ConfigurationErrorsException Обновлена документация для .
slolife

Ответы:

36

Вы не ограничены в генерировании исключений существующими исключениями в Framework. Если вы все же решите использовать существующие исключения, вам не обязательно строго следовать документации. В документации будет описано, как фреймворк использует данное исключение, но не будет никаких ограничений на то, как вы решите использовать / повторно использовать существующее исключение.

Это ваше приложение - если вы его задокументируете и четко укажете исключение, которое будет выдано в конкретном случае отсутствия значения конфигурации, вы можете использовать любое исключение, которое вам нравится. Если вам нужно очень конкретное указание на отсутствующее значение, вы можете подумать о написании собственного исключения ConfigurationSettingMissing:

[Serializable]
public class ConfigurationMissingException : ConfigurationErrorsException
{}

РЕДАКТИРОВАТЬ: написание собственного исключения в этом случае дает дополнительное преимущество, гарантируя, что никогда не будет путаницы относительно того, откуда исходит исключение - из фреймворка или вашего приложения. Фреймворк никогда не будет генерировать пользовательские исключения.

ОБНОВЛЕНИЕ: я согласен с комментариями, поэтому я изменил подкласс на ConfigurationErrorsException из Exception. Я думаю, что обычно рекомендуется создавать подклассы пользовательских исключений из существующих исключений Framework, где это возможно, избегая класса Exception, если вам не нужно исключение для конкретного приложения.

Дэйв Сверски
источник
17
Я несколько не согласен. Если вы собираетесь использовать существующее исключение, его следует использовать ТОЧНО, как указано в документации, иначе вы запутаете тех, кто придет после вас. Если вы собираетесь сделать что-то другое, просто создайте собственное исключение, как вы сказали.
Роберт С. Барт,
1
Я не согласен. Если у вас нет сценария для перехвата настраиваемого исключения, что маловероятно в случае ошибки конфигурации, лучше повторно использовать существующий тип (ConfigurationErrorsException). И если вы действительно создаете настраиваемый тип, я бы унаследовал его от связанного типа, такого как ConfigurationErrorsException.
Joe
@Robert & Joe: я не предлагаю, чтобы существующие исключения Framework использовались несовместимо с их предполагаемой функцией, просто существует некоторая гибкость, если конкретный случай (отсутствующее значение) соответствует общему случаю (ConfigurationErrorsException).
Дэйв Сверски, 06
1
С этим могут возникнуть проблемы, если вы генерируете исключение в приложении ASP.NET как ConfigurationErrorsException, а классы, производные от него, не попадают в защищенный метод OnError или событие Global ASAX Error. См. Этот вопрос, который я разместил .... stackoverflow.com/questions/25299325/…
Мик,
48

Лично я бы использовал InvalidOperationException , поскольку это проблема с состоянием объекта, а не с системой конфигурации. В конце концов, разве вы не должны позволять устанавливать эти параметры с помощью кода, а не конфигурации? Важная часть здесь заключается не в том, что в app.config не было строки, а в том, что не было необходимой информации.

Для меня ConfigurationException (и его замена, ConfigurationErrorsException - несмотря на вводящие в заблуждение документы MSDN) предназначены для ошибок при сохранении, чтении и т. Д. Configuration.

Марк Брэкетт
источник
Я выбрал InvalidOperationException, поскольку он обрабатывается методом OnError, защищенным страницей ASP.NET, в то время как исключение ConfigurationErrorsException и все исключения, производные от него, не являются,
Мик,
2
Это действительно удивит меня, если я получу исключение InvalidOperationException, если я ошибаюсь в конфигурации.
keuleJ
18

Как сказал Дэниел Ричардсон, следует использовать ConfigurationErrorsException . Как правило, рекомендуется создавать собственные настраиваемые типы исключений, только если у вас есть сценарий для их обработки. В случае ошибок конфигурации, которые обычно являются фатальными, это случается редко, поэтому обычно более целесообразно повторно использовать существующий тип ConfigurationErrorsException.

До .NET 2.0 рекомендовалось использовать System.Configuration.ConfigurationException . ConfigurationException устарело в .NET 2.0 по причинам, которые мне никогда не были понятны, и рекомендация была изменена на использование ConfigurationErrorsException.

Я использую вспомогательный метод для создания исключения, чтобы было легко изменить исключение, которое создается в одном месте при переходе с .NET 1.x на 2.0, или если Microsoft решит снова изменить рекомендацию:

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
        )
        );
}
Джо
источник
16

О чем System.Configuration.SettingsPropertyNotFoundException?

Laurent
источник
ИМО, это настоящий ответ. +1
LC
Не совсем, потому что: Предоставляет исключение для объектов SettingsProperty, которые не найдены. Откуда: используется внутри как класс, представляющий метаданные об отдельном свойстве конфигурации. Это не то же самое, что отсутствующее значение конфигурации.
Кароль Халински
7

ConfigurationErrorsException- правильное исключение для описанной вами ситуации. Более ранняя версия документации MSDN для ConfigurationErrorsException.

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

Предыдущее резюме и примечания MSDN:

  • Исключение, которое выдается при возникновении ошибки системы конфигурации.
  • ConfigurationErrorsException Исключение при возникновении ошибки во время сведения о конфигурации чтения или записи.
Дэниел Ричардсон
источник
7
из документации: «Этот API поддерживает инфраструктуру продукта и не предназначен для использования непосредственно из вашего кода. Инициализирует новый экземпляр класса ConfigurationErrorsException».
Олег Ш
6

Класс ConfigurationElement (который является базовым классом многих классов, связанных с конфигурацией, таких как ConfigurationSection) имеет метод OnRequiredPropertyNotFound (есть и другие вспомогательные методы). Вы можете назвать это.

OnRequiredPropertyNotFound реализован следующим образом:

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

Я бы выпил его и свернул свой собственный ... но прежде чем вы это сделаете, возможно ли, чтобы система приняла значение по умолчанию для этого параметра конфигурации? Я обычно пытаюсь сделать это для всех настроек, которые могут быть пропущены специалистами по управлению операциями ... (или, возможно, я должен сказать, для как можно большего количества настроек - для некоторых явно неуместно, чтобы система принимала решение по умолчанию. ..)

в общем, кастомное исключение не требует больших усилий ... вот пример ...

[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: ... приложение, которое должно создавать свои собственные исключения, [...] выводит настраиваемые исключения из класса Exception. Первоначально предполагалось, что настраиваемые исключения должны быть производными от класса ApplicationException; однако на практике не было обнаружено, что это существенно увеличивает ценность.
Гаспар Надь,
Да, я думаю, это произошло потому, что программисты MS, которые кодировали фреймворк, извлекли из ApplicationException многочисленные исключения CLR, тем самым разрушив значимость различия ... Я все еще делаю это, поскольку не вижу в этом вреда ...
Чарльз Бретана
1

Альтернативный метод, который вы могли бы использовать для своих файлов конфигурации, заключался бы в использовании настраиваемых разделов конфигурации вместо AppSettings. Таким образом вы можете указать, что свойство IsRequiredи система конфигурации будут выполнять эту проверку за вас. Если свойство отсутствует, оно выдаст ошибку, ConfigurationErrorsExceptionпоэтому я полагаю, что это подтверждает ответ, что вы должны использовать это исключение в своем случае.

Yogh
источник
0

Мое общее правило было бы таким:

  1. Если случай с отсутствующей конфигурацией не очень распространен, и я считаю, что никогда не хотел бы обрабатывать этот случай иначе, чем другие исключения, я просто использую базовый класс «Exception» с соответствующим сообщением:

    выбросить новое исключение («мое сообщение здесь»)

  2. Если я действительно хочу или думаю, что есть большая вероятность, что я захочу обработать этот случай иначе, чем большинство других исключений, я бы выбрал свой собственный тип, как здесь уже предлагали люди.

Херши
источник
0

Я склонен не соглашаться с предпосылкой вашего вопроса:

Короче говоря, мне нужно стандартное исключение, которое должно выдаваться, когда параметр конфигурации приложения отсутствует или содержит недопустимое значение. Можно подумать, что в Framework есть такое исключение, которое можно использовать в приложениях. (По-видимому, это было так, но оно было помечено как устаревшее и было заменено чем-то гораздо более масштабным.)

Согласно документации MSDN по System.Exception ( класс исключений , вам действительно не следует создавать исключения для ошибок ввода пользователя по причинам производительности (на что указали другие в Stack Overflow и в других местах). Это кажется логичным, поскольку хорошо - почему ваша функция не может вернуть false, если пользовательский ввод введен неправильно, а затем приложение корректно завершает работу? Это больше похоже на проблему дизайна, чем на проблему, с которой исключить исключение.

Как указывали другие, если вам действительно нужно вызвать исключение - по какой-либо причине - нет никаких причин, по которым вы не могли бы определить свой тип исключения путем наследования от System.Exception.

Мэтт Джордан
источник
2
Почему именно производительность имеет значение в этом конкретном сценарии? IUC, то исключение генерируется ровно один раз, и процесс, вероятно, в любом случае остановится (конечно, после показа пользователю красивого всплывающего окна). (продолжение следует ...)
2
Возврат кода ошибки вместо выдачи исключения может быть болезненным, потому что тогда вам придется самостоятельно распространять информацию об ошибке вверх по стеку вызовов. Вы должны использовать исключения для относительно редких ошибок, которые могут распространяться на несколько кадров стека. Оба применимы здесь.
1
Вы что-то упустили: «когда параметр конфигурации приложения отсутствует или содержит недопустимое значение», это не то же самое, что неправильный ввод пользователя. Это отсутствующая базовая конфигурация. Это должно быть настраиваемое исключение, которое должно останавливать запуск приложения.
jcollum 06
2
В этом конкретном приложении это почти полностью зависит от настроек в файле конфигурации. Если в нем нет настроек (где они зашифрованы), приложение не может продолжить работу и должно завершиться. Фактически требуется исключение.
Майк Хофер,
1
Это, безусловно, может попасть в семантику, и структура вашего кода, очевидно, будет определять лучшую реализацию для вашей ситуации. Тем не менее, если бы у вас была свобода в дизайне, я бы все равно использовал объект для регистрации ошибки и плавный выход из исключения, независимо от того, является ли производительность проблемой или нет.
Мэтт Джордан,
-2

Вы можете попробовать унаследовать исключение XML или просто использовать его.

StingyJack
источник