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

125

Чтение и запись разделов конфигурации в коде

ASP.NET предоставляет класс WebConfigurationManager в пространстве имен System.Web.Configuration, который позволяет извлекать информацию из конфигурационного файла во время выполнения. Члены WebConfigurationManager перечислены ниже:

AppSettings

Обеспечивает доступ к любой специальной информации, которая была добавлена в раздел <appSettings> конфигурационного файла приложения. Отдельные параметры предоставляются в виде проиндексированной по именам коллекции.

ConnectionStrings

Обеспечивает доступ к данным в разделе <connectionStrings> конфигурационного файла. Отдельные параметры предоставляются в виде проиндексированной по именам коллекции.

GetSection()

Возвращает объект, который содержит в себе информацию из конкретного раздела конфигурационного файла.

OpenWebConfiguration()

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

OpenMachineConfiguration()

Возвращает редактируемый объект Configuration, который предоставляет доступ к конфигурационной информации, которая была указана для веб-сервера (в файле machine.config)

Класс WebConfigurationManager предоставляет удобный доступ к двум разделам конфигурационного файла: <appSettings>, в котором можно определять специальные параметры, и <connectionStrings>, который можно использовать для указания того, как приложение подключается к базе данных. Он позволяет извлекать эту информацию с помощью свойств AppSettings и ConnectionStrings.

Используя метод WebConfigurationManager.GetSection(), можно извлекать информацию о любом другом разделе конфигурации, однако понадобится приложить дополнительные усилия. Хитрость состоит в том, что метод GetSection() возвращает объект с типом, который зависит от типа целевого раздела. Например, в случае извлечения информации из раздела <authentication> это будет объект AuthenticationSection, как показано ниже:

// Поиск элемента <authentication> внутри элемента <system.web>. 
AuthenticationSection authSection =
      (AuthenticationSection)WebConfigurationManager.GetSection("system.web/authentication"); 

Поиск реализован с помощью синтаксиса, похожего на синтаксис пути. Корневой элемент <configuration> нe указывается, поскольку все разделы конфигурации содержатся именно в этом элементе.

Определения классов для каждого раздела конфигурации находятся в библиотеке классов внутри пространства имен System.Web.Configuration (а не System.Configuration, которое включает только классы конфигурации, общие для всех приложений .NET). Все эти классы унаследованы от ConfigurationSection.

Использование объекта ConfigurationSection позволяет извлекать немало информации о текущем состоянии приложения. Ниже приведен пример отображения с помощью этого объекта информации обо всех сборках, на которые в текущий момент ссылается приложение (используя синтаксис LINQ):

((CompilationSection)WebConfigurationManager.GetSection("system.web/compilation"))
                 .Assemblies.OfType<AssemblyInfo>().ToList()
                 .ForEach(p => { Response.Write(p.Assembly + "<br/>"); });
Получение ссылок на сборки

При извлечении информации с использованием метода GetSection(), он отражает совокупную конфигурацию текущего приложения. Это означает, что параметры из текущего файла web.config объединяются с теми, которые определены выше в иерархии конфигурации (например, в корневом файле web.config и в machine.config).

С помощью класса WebConfigurationManager можно также изменять большинство разделов конфигурации в коде: в действительности ASP.NET полагается на эту функциональность в административных веб-страницах. Для использования этого подхода сначала нужно вызывать метод OpenWebConfiguration() для получения объекта Configuration. Затем посредством метода Configuration.GetSection() можно извлечь раздел, предназначенный для модификации, и методом Configuration.Save() зафиксировать изменения. При изменении параметра настройки ASP.NET обрабатывает обновление безопасным образом, применяя специальный код синхронизации, который исключает возможность фиксации изменения одновременно несколькими клиентами.

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

Инструмент Website Administration Tool (WAT)

Вас наверняка интересует, зачем команде разработчиков ASP.NET понадобилось создавать такой сложный инструмент, как WebConfigurationManager, который работает слишком плохо для того, чтобы его можно было использовать в обычном веб-приложении. Причина в том, что WebConfigurationManager на самом деле не предназначен для применения в веб-страницах. Вместо этого он позволяет разработчикам создавать специальные инструменты, упрощающие конфигурирование веб-приложений.

ASP.NET даже включает графический инструмент конфигурирования, который основан полностью на WebConfigurationManager, хотя узнать об этом можно, только углубившись в код. Этот инструмент называется WAT (Website Administration Tool — инструмент для администрирования веб-сайта). Он позволяет конфигурировать различные части файла web.config с помощью интерфейса веб-страницы.

Чтобы запустить его для конфигурирования текущего приложения в Visual Studio, выберите в меню Website (Веб-сайт) (или в меню Project (Проект) в случае проектной разработки) пункт ASP.NET Configuration (Конфигурация ASP.NET). После этого Visual Studio откроет окно браузера, который автоматически аутентифицирует вас с текущей учетной записью:

Запуск инструмента WAT

WAT можно использовать для автоматизации изменений web.config, сделанных в предыдущем примере. Для этого перейдите на вкладку Application (Приложение). Эта вкладка позволяет редактировать и удалять параметры приложения (щелчком на ссылке Manage Application Settings (Управление параметрами настройки приложения)), а также создавать новые параметры (щелчком на ссылке Create Application Settings (Создание параметров настройки приложения)):

Редактирование параметра настройки приложения с помощью WAT

Вот так работа WAT, по сути, и выглядит: вы вносите изменения с помощью графического интерфейса (веб-страницы), a WAT "за кулисами" генерирует все необходимые параметры и добавляет их в файл web.config приложения. Конечно, в WAT также имеется ряд опций для конфигурирования более сложных параметров ASP.NET.

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

Ранее было показано, как применять элемент <appSettings> для хранения специальной информации, которая должна использоваться в приложении. Однако с этим элементом связаны два серьезных ограничения. Во-первых, он не позволяет хранить структурированную информацию, такую как списки или группы связанных параметров. Во-вторых, он не позволяет использовать разные типы данных. Он ограничен только одиночными строками.

К счастью, в ASP.NET применяется модульная модель конфигурации с высокой степенью расширяемости, которая позволяет расширять структуру конфигурационных файлов web.config и machine.config добавлением в них собственных специальных разделов. Чтобы расширить структуру конфигурационного файла, понадобится выполнить три следующих шага:

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

  2. Для каждого нового элемента создайте класс C#, инкапсулирующий его информацию. При запуске приложения ASP.NET будет считывать информацию из элемента в конфигурационном файле и использовать ее для создания экземпляра класса. После этого вы можете читать информацию из этого объекта всякий раз, когда в ней возникает необходимость.

  3. Зарегистрируйте новый раздел в своем конфигурационном файле с использованием элемента <configSections>. В <configSections> каждый новый элемент идентифицируется и отображается на соответствующий класс.

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

Создание класса раздела

Предположим, что необходимо сохранить несколько связанных параметров, которые все вместе будут указывать приложению, каким образом ему связываться с удаленным объектом. Например, эти параметры могут содержать номер порта, информацию о местонахождении сервера, URL-адрес, данные об аутентификации пользователей и т.д. Исходя из уже изученного, можно ввести их как отдельные параметры в разделе <appSettings>. Однако тогда ничто не будет указывать на логическую связь между этими параметрами. Это не только усложнит их чтение и интерпретацию, но может привести к возникновению проблем, если один из них обновляется, а всех остальные — нет.

Поэтому лучше отказаться от ограниченной структуры раздела <appSection> и поместить всю необходимую информацию в один XML-элемент. Ниже показан пример, в котором определяется специальный элемент <orderService>:

<orderService available="true" pollTimeout="00:01:00"
                location="tcp://OrderComputer:8010/OrderService/"/>

Если вы хотите использовать такую структуру, то должны определить соответствующий класс, унаследовав его от System.Configuration.ConfigurationSection. Далее можно как поместить этот класс в отдельный DLL-компонент, так и добавить его исходный код в папку App_Code, чтобы он автоматически компилировался как часть текущего веб-приложения. (Если вы создаете приложение в виде веб-проекта, просто добавьте файл исходного кода в этот проект, и он будет автоматически компилироваться как часть сборки веб-приложения.)

Ниже показан подходящий для приведенного выше примера класс OrderService. Он представляет один единственный элемент <orderService> и предоставляет доступ к его атрибутам через строго типизированные свойства:

using System;
using System.Configuration;

public class OrderService : ConfigurationSection
{
        [ConfigurationProperty("available",
            IsRequired = false, DefaultValue = true)]
        public bool Available
        {
            get { return (bool)base["available"]; }
            set { base["available"] = value; }
        }

        [ConfigurationProperty("pollTimeout",
            IsRequired = true)]
        public TimeSpan PollTimeout
        {
            get { return (TimeSpan)base["pollTimeout"]; }
            set { base["pollTimeout"] = value; }
        }

        [ConfigurationProperty("location",
            IsRequired = true)]
        public string Location
        {
            get { return (string)base["location"]; }
            set { base["location"] = value; }
        }
}

Здесь видно, что каждое свойство отображается на имя соответствующего атрибута с помощью атрибута ConfigurationProperty. Эта часть кода чрезвычайно важна, поскольку определяет схему (структуру) специального раздела. Если добавить атрибут в специальный раздел, но не включить соответствующий атрибут ConfigurationProperty, то при попытке прочитать эту часть файла web.config ASP.NET сгенерирует исключение.

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

Регистрация класса раздела

После создания класса раздела никакого кода больше писать не понадобится. Однако еще остается зарегистрировать этот класс в файле web.config, чтобы среда ASP.NET могла распознать добавленные специальные параметры. Если не выполнить этот шаг, при попытке запустить приложение возникнет ошибка, потому что ASP.NET заметит в файле web.config неизвестный раздел.

Чтобы зарегистрировать свой специальный раздел, просто добавьте элемент <section> в раздел <configSections> файла web.config и укажите в нем имя раздела (с использованием атрибута name) и имя соответствующего ему класса (с помощью атрибута type).

Ниже показано содержимое файла web.config:

<configuration>
  
  <configSections>
    <section name="orderService" type="OrderService"/>
  </configSections>
...

И, наконец, последнее, что понадобится сделать — это обеспечить извлечение в вебстранице информации из специального раздела на тех этапах, где она необходима. Для этого нужно использовать метод ConfigurationManager.GetSection():

protected void Page_Load(object sender, EventArgs e)
{
            OrderService custSection =
                (OrderService)ConfigurationManager.GetSection("orderService");

            txt1.Text = "Извлеченная информация из web.config/orderService... <br/><br/>"
                + "<b>Location:</b> " + custSection.Location + 
                "<br /><b>Available:</b> " + custSection.Available.ToString() + 
                "<br /><b>Timeout:</b> " + custSection.PollTimeout.ToString() + "<br /><br />";
}

На рисунке показано, какие данные будут отображаться:

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

Шифрование разделов конфигурации

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

В ASP.NET поддерживаются два варианта шифрования:

RSA

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

DPAPI (data protection API — API-интерфейс защиты данных)

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

В любой из этих схем шифрование является совершенно прозрачным. Когда вы получаете параметр настройки из зашифрованного раздела, ASP.NET автоматически расшифрует его и вернет коду простой текст (при условии доступности требуемого ключа).

Точно так же, если вы модифицируете значение программно и сохраняете его, шифрование происходит автоматически. Однако вы не сможете редактировать этот раздел файла web.config вручную. Хотя вы по-прежнему можете пользоваться WAT, IIS Manager или собственным специальным кодом. При работе с API-интерфейсом конфигурации шаги шифрования и расшифровки выполняются автоматически во время чтения или записи в защищенный раздел.

Шифрование в коде

Чтобы разрешить шифрование программным путем, необходимо извлечь соответствующий объект ConfigurationSection.SectionInformation, а затем вызвать метод ProtectSection(). Любые существующие данные будут зашифрованы, и с этого момента любые производимые изменения будут шифроваться автоматически. Чтобы отключить шифрование, вызовите метод UnprotectSection().

Ниже показан пример, в котором производится шифрование раздела приложения, если он не зашифрован, или отключение шифрования, если он зашифрован:

Configuration config = WebConfigurationManager.OpenWebConfiguration("/");
ConfigurationSection appSettings = config.GetSection("appSettings");

if (appSettings.SectionInformation.IsProtected)
     appSettings.SectionInformation.UnprotectSection();
else
     appSettings.SectionInformation.ProtectSection("DataProtectionConfigurationProvider");

config.Save();

Шифрование из командной строки

На данный момент не существует никакого графического инструментального средства для шифрования и расшифровки параметров настройки конфигурационного файла. Но если вы не хотите писать код, можете воспользоваться утилитой командной строки aspnet_regiis.exe, которая находится в каталоге c:\Windows\Microsoft.NET\Framework\[версия]. Для использования этого инструмента уже должен быть создан виртуальный каталог, чтобы настроить приложение в IIS.

При использовании утилиты aspnet_regiis для защиты части конфигурационного файла потребуется определить следующие аргументы командной строки:

Ниже показана командная строка, которая дублирует приводимый ранее пример для приложения по адресу http://localhost/TestApp:

aspnet_regiis -pe "appSettings" -app "/TestApp" 
   -prov "DataProtectionConfigurationProvider"
Пройди тесты
Лучший чат для C# программистов