.NET: Яке виключення для викидання, коли потрібна настройка конфігурації відсутня?


123

Ось стандартний сценарій:

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

Проблема полягає в тому, що я не зовсім певний, якимSomeStandardException має бути виняток .

Я ознайомився з Рамкою 3.5 і знайшов двох ймовірних кандидатів: ConfigurationExceptionі ConfigurationErrorsException.

System.Configuration.ConfigurationException

Виняток, який видається, коли сталася помилка системи конфігурації.

Зауваження

ConfigurationExceptionВиняток , якщо додаток намагається зчитувати або записувати дані в файл конфігурації , але безуспішно. Деякі можливі причини цього можуть включати неправильно сформований XML у файлі конфігурації, проблеми з дозволом файлів та властивості конфігурації зі значеннями, які не є дійсними.

Примітка:

ConfigurationExceptionОб'єкт підтримується для зворотної сумісності. ConfigurationErrorsException Об'єкт замінює його для конфігурації системи.

Цей виняток насправді звучить ідеально для того, що мені потрібно, але він був позначений застарілим, значить, ixnay on atthay.

Це приводить нас до ретельно дивовижних ConfigurationErrorsException:

System.Configuration.ConfigurationErrorsException

Поточне значення не є одним із значень EnableSessionState.

Як бачите, його документація є абсолютно марною. (Це так і в локальній, і в онлайн-довідці.) Експертиза самого класу показує, що це надмірно надмірна оцінка того, чого я хочу.

Коротше кажучи, мені потрібен стандартний виняток, який слід викинути, коли параметр конфігурації програми відсутній або містить недійсне значення. Ви можете подумати, що у Рамці був застосований такий виняток для використання програм. (Мабуть, це було, але воно було відмічене застарілим, і його замінило щось значно більше за обсягом.)

Які рішення, якщо такі є, ви, хлопці, використовуєте для цього, і мені доведеться це висмоктати і перекласти власний виняток для цього?

Редагувати доповнення

Деякі запитували, чи можу я вказати значення за замовчуванням чи ні, і продовжувати. У певних випадках, так, і в тих випадках виняток не буде кинутий. Однак для певних налаштувань це не стосується. Наприклад: імена та облікові дані серверів бази даних, сервери аутентифікації та шляхи до встановлених сторонніх додатків.

Варто також зазначити, що програма, над якою я в основному працюю, - це консольний додаток, що працює в пакетному режимі, і я хочу, щоб він викинув виняток, який потрапляє в основний метод і реєструється належним чином, якщо річ не налаштована належним чином. (Це спадковий код, який я успадкував, і наразі просто передбачає, що все персично.)


1
Документація на System.Configuration.ConfigurationErrorsException оновлено.
slolife

Відповіді:


36

Ви не обмежуєтесь тим, що викидаєте виключення на існуючі винятки в Рамці. Якщо ви все-таки вирішите використовувати існуючі винятки, вам зовсім не доведеться дотримуватися документації до листа. Документ описує , яким чином структура використовує цей виняток, але не має на увазі будь - які обмеження на те, як ви вибираєте для використання / повторного використання існуючого виключення.

Це ваша програма - доки ви документуєте її і чітко вказуєте на виняток, який буде викинутий у конкретному випадку відсутнього значення конфігурації, ви можете використовувати будь-який виняток, який вам подобається. Якщо ви хочете дуже конкретно вказати на відсутність значення, ви можете розглянути можливість написання власного винятку ConfigurationSettingMissing:

[Serializable]
public class ConfigurationMissingException : ConfigurationErrorsException
{}

РЕДАКТУВАННЯ: Написання власного винятку в даному випадку несе в собі додаткову перевагу, гарантуючи, що ніколи не буде плутанини щодо того, звідки виняток виходить із рамки чи вашої заявки. Рамка ніколи не кине ваші власні винятки.

ОНОВЛЕННЯ: Я погоджуюся з коментарями, тому я змінив підклас на ConfigurationErrorsException from Exception. Я думаю, що, як правило, корисно підкласи виняткових спеціальних винятків із існуючих винятків Framework, де це можливо, уникаючи класу «Винятки», якщо вам не потрібне виключення для програми.


17
Я дещо не згоден. Якщо ви збираєтесь використовувати існуючий виняток, його слід використовувати ТОЧНО, оскільки документація говорить про його використання, інакше ви будете плутати тих, хто йде за вами. Якщо ви збираєтеся робити щось інше, просто створіть власний виняток, як ви сказали.
Роберт К. Барт

1
Я не погоджуюсь. Якщо у вас є сценарій вилучення власного винятку, навряд чи у випадку помилки конфігурації, краще повторно використовувати існуючий тип (ConfigurationErrorsException). І якщо ви створюєте власний тип, я отримав би його із пов'язаного типу, такого як ConfigurationErrorsException.
Джо

@Robert & Joe - Я не припускаю, що існуючі винятки Framework повинні використовуватися невідповідно до призначеної функції, лише якщо існує певна гнучкість, доки конкретний випадок (відсутнє значення) відповідає загальному випадку (ConfigurationErrorsException).
Дейв Сверський

1
З цим можуть виникнути проблеми, якщо ви викидаєте виняток у програму ASP.NET як ConfigurationErrorsException, а класи, похідні від нього, не потрапляють у захищений метод OnError або в події Global ASAX Error. Дивіться це запитання, яке я опублікував .... stackoverflow.com/questions/25299325/…
Мік

48

Особисто я би використовував InvalidOperationException , оскільки це проблема зі станом об'єкта - не системою конфігурації. Зрештою, чи не слід дозволити ці параметри встановлювати за кодом, а також не конфігурувати? Важлива частина тут не в тому, що в app.config не було рядка, а в тому, що потрібної інформації не було.

Для мене ConfigurationException (і це заміна, ConfigurationErrorsException - незважаючи на оманливі документи MSDN) - це помилки в збереженні, зчитуванні та ін.


Я вибрав 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

ІМО, це справжня відповідь. +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

Я б висмоктав його і прокрутив свій власний ... але перед тим, як це зробити, чи можливо система припустить значення для цього налаштування за замовчуванням? Я, як правило, намагаюся зробити це для кожного параметра, який може бути пропущений bu Ops Management folk ... (або, можливо, слід сказати, для якомога більшої кількості налаштувань - для деяких явно не доцільно система приймати рішення за замовчуванням. ..)

загалом, спеціальне виключення - це не багато зусиль ... ось приклад ...

[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, які зашифрували рамки, отримали численні винятки CLR з ApplicationException, тим самим знищивши значення відмінності .. Я все одно це роблю, хоча, як не бачу в цьому шкоди ...
Чарльз Бретана

1

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


0

Моє загальне правило:

  1. Якщо випадок відсутньої конфігурації не дуже поширений, і я вважаю, що я ніколи не хотів би вирішувати цей випадок інакше, ніж інші винятки, я просто використовую базовий клас "Виняток" з відповідним повідомленням:

    кинути новий виняток ("моє повідомлення тут")

  2. Якщо я хочу, або вважаю, що є велика ймовірність, що я хотів би розглянути цю справу іншим чином, ніж більшість інших винятків, я би переклав власний тип, як люди вже запропонували тут.


0

Я схильний не погоджуватися з передумовою вашого питання:

Коротше кажучи, мені потрібен стандартний виняток, який слід викинути, коли параметр конфігурації програми відсутній або містить недійсне значення. Ви можете подумати, що у Рамці був застосований такий виняток для використання програм. (Мабуть, це було, але воно було відмічене застарілим, і його замінило щось значно більше за обсягом.)

Відповідно до документації MSDN про System.Exception ( клас винятку) винятку, ви насправді не повинні викидати винятки для помилок введення користувача, з міркувань продуктивності (на що вказували інші в Stack Overflow та інших місцях). Це, мабуть, має сенс, оскільки добре - чому ваша функція не може повернути помилкову, якщо введення користувача введено неправильно, а потім програма виграшно вийде?

Як зазначали інші, якщо вам дійсно доведеться кинути виняток - з будь-якої причини - немає жодної причини, чому ви не могли б визначити тип винятку, успадкувавши від System.Exception.


2
Чому саме в цьому конкретному сценарії матиме значення продуктивність? IUC, тоді виняток викидається рівно один раз, і процес, швидше за все, згодом знизиться (звичайно, після показу приємного спливаючого вікна користувачеві). (буде продовжено ...)

2
Повернення коду помилки замість того, щоб викидати виняток, може бути болючим, оскільки тоді вам доведеться самостійно поширювати інформацію про помилку в стек виклику. Ви повинні використовувати винятки для відносно рідкісних помилок, які можуть бути розповсюджені на декількох кадрах стека. Тут застосовується і те й інше.

1
Ви щось пропустили: "коли параметр конфігурації програми відсутній або містить недійсне значення", це не те саме, що неправильний ввід користувача. Це основна конфігурація, якої немає. Повинен бути спеціальним винятком і повинен зупиняти роботу програми.
jcollum

2
У цьому конкретному додатку майже повністю керуються налаштуваннями у файлі конфігурації. Якщо в ньому немає налаштувань (там, де вони зашифровані), додаток не може продовжуватися, а його потрібно припинити. Виняток практично не потрібен.
Майк Хофер

1
Це, безумовно, може ввійти в семантику, і структура вашого коду, очевидно, буде диктувати найкращу реалізацію для вашої ситуації. Тим не менш, якби у вас було вільне управління дизайном, я б все-таки пішов з об'єктом, щоб зафіксувати помилку і витончений вихід над винятком, продуктивність - це проблема чи ні.
Метт Джордан

-2

Ви можете спробувати успадкувати виняток XML або просто використовувати його.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.