Разделы конфигурации

188

Конфигурационный файл Web.config образован из разделов конфигурации, а некоторые из этих разделов упакованы в группы разделов конфигурации. Примерами разделов конфигурации могут служить элементы <appSettings> и <connectionStrings>, а в качестве примера группы разделов можно привести элемент <system.Web>.

Чтобы выяснить, что собой представляет интересующий элемент, нужно взглянуть, где он определен в иерархии конфигурационных файлов. Для примера предположим, что в приложении необходимо знать значение атрибута debug элемента <compilation>, который определен в файле Web.config следующим образом:

...
  <system.web>
    <compilation debug="true" targetFramework="4.5.1" />
    <httpRuntime targetFramework="4.5.1" />
  </system.web>
...

Это один из элементов, которые Visual Studio добавляет в файл Web.config при создании нового проекта. Элемент system.web является группой разделов, а элемент compilation - разделом. Как мы узнали это? Мы просмотрели файл Machine.config, где определено большинство важных разделов и групп разделов конфигурации:

...
<sectionGroup name="system.web" 
    type="System.Web.Configuration.SystemWebSectionGroup">
    
	...
	
    <section name="compilation" type="System.Web.Configuration.CompilationSection" 
	    requirePermission="false"/>
    
	...

</sectionGroup>
...

Мы не показали элементы, определяющие другие разделы, и части значений атрибута type, в которых указано, в какой сборке определен тот или иной класс. Тем не менее, базовая структура осталась вполне понятной - элемент sectionGroup используется для определения system.web, а элемент section служит для определения compilation. Подробные сведения об этих элементах будут представлены при создании собственных разделов и групп далее.

Обратите внимание, что в элементе section, определяющем раздел compilation, не указаны атрибуты, которые определены в элементе compilation. Это обрабатывается классом, заданным с помощью атрибута type элемента section - в данном примере System.Web.Configuration.CompilationSection. Такой класс называется обработчиком раздела. Способы применения этого класса рассматриваются в последующих разделах.

Получение одиночного раздела

Простейший способ получения конфигурационной информации из раздела предусматривает вызов методов WebConfigurationManager.GetWebApplicationSection() или GetSection(). В качестве аргумента этим методам передается имя интересующего раздела, выраженное в виде пути относительно элемента <configuration>. Отличие между методами в том, что GetWebApplicationSection() проигнорирует любые параметры конфигурации, специфичные для папок, в то время как GetSection() примет их во внимание.

В данном примере нас интересует раздел <compilation>, а конфигурация папок не применяется. Следовательно, мы должны воспользоваться методом GetWebApplicationSection() и указать ему раздел system.web/compilation:

using System.Web.Configuration;
using System.Collections.Generic;

namespace ConfigFiles
{

    public partial class Default : System.Web.UI.Page
    {
        public IEnumerable<string> GetConfig()
        {
            object config = WebConfigurationManager
                .GetWebApplicationSection("system.web/compilation");
            CompilationSection section = config as CompilationSection;

            if (section != null)
            {
                yield return string.Format("debug = {0}<br>targetFramework = {1}<br>batch = {2}",
                    section.Debug, section.TargetFramework, section.Batch);
            }
            else
            {
                yield return string.Format("Неправильный тип конфигурации: {0}",
                    config.GetType());
            }
        }
    }
}

Метод GetWebApplicationSection() возвращает в результате экземпляр типа object, и мы сами отвечаем за его приведение к типу, заданному элементом section. Это еще одна причина нахождения элемента section для требуемой конфигурационной информации. Необходимо знать, какой класс обработчика раздела следует ожидать от класса WebConfigurationManager. (Мы считаем, что такое неудачное и неудобное проектное решение для взаимодействия с конфигурационными данными заставляет многих разработчиков обращаться к менее подходящим альтернативам, таким как статически определенные значения или данные приложения.)

Классы обработчиков для всех специфических разделов ASP.NET находятся в пространстве имен System.Web.Configuration. Некоторые разделы используются более широко, поэтому классы их обработчиков следует искать в пространстве имен System.Configuration.

В примере выше мы аккуратно приводим полученный из метода GetWebApplicationSection() экземпляр типа object к типу CompilationSection, который представляет собой класс обработчика, указанного в элементе section для раздела compilation внутри файла Machine.config. Затем можно прочитать конфигурационные значения, которые доступны через свойства класса CompilationSection.

В примере возвращаются значения свойств Debug, TargetFramework и Batch, соответствующие атрибутам debug, targetFramework и batch. Значения атрибутов debug и targetFramework указаны в файле Web.config уровня приложения, но значение для атрибута batch не задано, поэтому применяется его стандартное значение. Мы объясним, как это работает, во время создания собственных разделов конфигурации.

Разделы конфигурации можно также получать с помощью метода HttpContext.GetSection(), который эквивалентен методу WebConfigurationManager.GetWebApplicationSection(). Нам больше нравится пользоваться классом WebConfigurationManager, но это вопрос личных предпочтений.

Чтобы увидеть результат, запустите приложение и запросите веб-форму Default.aspx:

Отображение значений из конфигурационных разделов

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

using System.Web.Configuration;
using System.Collections.Generic;

namespace ConfigFiles
{

    public partial class Default : System.Web.UI.Page
    {
        public IEnumerable<string> GetConfig()
        {
            yield return DebugEnabled ? "Отладка включена" : "Отладка выключена";
        }

        public bool DebugEnabled
        {
            get
            {
                return (WebConfigurationManager
                    .GetWebApplicationSection("system.web/compilation") as CompilationSection).Debug;
            }
        }
    }
}

Здесь было определено свойство только для чтения по имени DebugEnabled, которое отвечает за получение объекта обработчика раздела и чтение значения свойства Debug. Приведение экземпляра object, возвращенного методом GetWebApplicationSection() к типу CompliationSection требовало намного меньшей осторожности. Это вполне допустимо в случае проверенной команды разработки проектов. В менее зрелых командах разработчиков мы стараемся проявлять большую внимательность.

Работа с полной конфигурацией

Большую часть времени вы будете искать значение атрибута, примененного к указанному разделу конфигурации, как это делалось с атрибутом debug в разделе <compilation>. Чтобы просмотреть полную конфигурацию, можно воспользоваться методом WebConfigurationManager.OpenWebConfiguration(), как показано в примере ниже:

using System.Web.Configuration;
using System.Collections.Generic;
using System.Configuration;

namespace ConfigFiles
{

    public partial class Default : System.Web.UI.Page
    {
        public IEnumerable<string> GetConfig()
        {
            Configuration config
                = WebConfigurationManager.OpenWebConfiguration(Request.Path);

            SystemWebSectionGroup group = 
                config.SectionGroups["system.web"] as SystemWebSectionGroup;

            yield return string.Format("debug = {0}<br>targetFramework = {1}<br>batch = {2}",
                    group.Compilation.Debug, 
                    group.Compilation.TargetFramework, 
                    group.Compilation.Batch);
        }
    }
}

Метод OpenWebConfiguration() принимает аргумент пути и позволяет задавать уровень, на котором должна читаться конфигурация. С помощью свойства Request.Path был получен путь для текущего запроса. Поскольку текущий запрос относится к веб-форме Default.aspx, это приводит к проходу по иерархии вниз до файла Web.config уровня приложения, исключая элементы location и файлы на уровне папок (на том же уровне мы работали в предшествующих примерах).

Если интересует конфигурация для папки, понадобится передать в качестве аргумента путь к этой папке, используя нотацию с тильдой (~), которая была описана в статье "Работа с путями". Таким образом, аргумент "~/Admin", к примеру, будет учитывать элемент location, добавленный в файл Web.config ранее.

Метод OpenWebConfiguration() возвращает объект System.Configuration.Configuration, который предоставляет обзор полной конфигурации, включая группы разделов. В таблице ниже перечислены наиболее часто применяемые члены, определенные в классе Configuration:

Свойства и методы, определенные в классе Configuration
Имя Описание
SectionGroups

Возвращает коллекцию объектов ConfigurationSectionGroup, индексированную по имени

Sections

Возвращает коллекцию объектов ConfigurationSection индексированную по имени

GetSection()

Возвращает объект ConfigurationSection для указанного раздела

GetConfigurationGroup()

Возвращает объект ConfigurationSectionGroup для указанной группы разделов

Группы разделов представлены классами обработчиков групп разделов. Например, группа разделов system.web обрабатывается классом SystemWebSectionGroup, в котором определены свойства для каждого содержащегося в ней раздела. Свойство Compilation возвращает объект CompilationSection, как показано в примере ниже:

using System.Web.Configuration;
using System.Collections.Generic;
using System.Configuration;

namespace ConfigFiles
{

    public partial class Default : System.Web.UI.Page
    {
        public IEnumerable<string> GetConfig()
        {
            Configuration config
                = WebConfigurationManager.OpenWebConfiguration(Request.Path);

            SystemWebSectionGroup group = 
                config.SectionGroups["system.web"] as SystemWebSectionGroup;

            CompilationSection compileSection = group.Compilation;

            yield return string.Format("debug = {0}<br>targetFramework = {1}<br>batch = {2}",
                    compileSection.Debug,
                    compileSection.TargetFramework,
                    compileSection.Batch);
        }
    }
}

Работа с классом Configuration несколько отличается от применения разделов из класса WebConfigurationManager, т.к. мы получаем объекты, типизированные базовыми классами, которые используются для описания разделов и групп разделов.

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

Свойства, определенные в классе ConfigurationSectionGroup
Имя Описание
CurrentConfiguration

Возвращает объект Configuration, ассоциированный с группой разделов

Name

Возвращает имя группы разделов

IsDeclared

Возвращает true, если группа разделов определена на уровне, указанном в аргументе метода OpenWebConfiguration(). Значение false указывает на то, что группа разделов унаследована из файла, находящегося на более высоком уровне иерархии

SectionGroups

Возвращает коллекцию групп разделов, вложенных внутри данной группы разделов

Sections

Возвращает коллекцию разделов, определенных внутри данной группы разделов

Type

Возвращает имя подкласса ConfigurationSectionGroup, используемого в качестве обработчика для данной группы раздела

Класс ConfigurationSection удобен только для реализации разделов. Он не особенно поможет когда дело доходит до навигации в рамках конфигурации, предлагая только свойство SectionInformation, которое возвращает объект SectionInformation. Этот объект содержит базовую информацию о разделе и имеет свойства, описанные в таблице ниже:

Свойства, определенные в классе ConfigurationSection
Свойство Описание
IsDeclared

Возвращает true, если раздел определен на уровне, указанном в аргументе метода OpenWebConfiguration(). Значение false указывает на то, что раздел унаследован из файла, находящегося на более высоком уровне иерархии

Name

Возвращает имя раздела

Type

Возвращает имя подкласса ConfigurationSection, используемого в качестве обработчика для данного раздела

С помощью свойств классов Conf igurationSection и CorifigurationSectionGroup можно проходить по конфигурации. При этом требуется применять немного странный подход к кодированию, поскольку группы разделов могут содержать смесь разделов и других групп разделов.

Использование внешних конфигурационных файлов

Атрибут configSource позволяет помещать части конфигурации в разные файлы. В крупном проекте файл уровня приложения может стать громоздким, особенно если определяются специальные разделы и группы. Возможность разнесения конфигурации по нескольким файлам может упростить разработку. Мы видели применение этого приема в ситуации, когда разные команды разработчиков отвечали за фрагменты полной конфигурации, что позволило избежать проблем с разрешением конфликтующих обновлений файла Web.config.

Для демонстрации этой возможности мы добавили в проект новый файл по имени AppSettings.config, используя шаблон элемента Web Configuration File (Файл веб-кон-фигурации) в Visual Studio. Содержимое этого файла приведено в примере ниже:

<appSettings>
  <add key="dbConnectionString" value="defaultConnection" />
  <add key="defaultCity" value="Москва" />
  <add key="defaultCountry" value="Россия" />
  <add key="defaultLanguage" value="Русский" />
</appSettings>

Мы просто скопировали элемент appSettings вместе с его дочерними элементами из файла Web.config в файл AppSettings вместе с его дочерними элементами из файла Web.config в файл AppSettings.config (без элемента xml или configuration). Затем мы указали ASP.NET, где искать контент элемента appSettings, с помощью атрибута configSource в файле Web.config:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  ...
  <appSettings configSource="AppSettings.config" />
  ...
</configuration>

Благодаря этому простому изменению, мы получили возможность переместить часть конфигурации из файла Web.config.

С атрибутом configSource связан ряд ограничений. Во-первых, он может применяться только к разделам конфигурации, но не к группам разделов или элементам configSection, sectionGroup и section, используемым для определения специальных разделов и групп. Во-вторых, каждый внешний файл может служить для определения только одного раздела конфигурации. Например, используемый здесь файл AppSettings.config может содержать только элемент appSettings. Для каждого раздела конфигурации, который нужно переместить в Web.config, понадобится создавать новый файл.

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

Лучший чат для C# программистов