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

69

Ранее мы объяснили, каким образом конфигурационные файлы организуются в иерархию и затем объединяются с целью создания полной конфигурации для приложения. Мы показали, как использовать атрибуты allowDefinition и allowLocation для управления тем, в каких местах разделы могут применяться. Однако мы можем пойти еще дальше и блокировать значения после их определения, чтобы предотвратить их изменение на более низких уровнях иерархии конфигурации. Эта часть конфигурации называется блокированием. Атрибуты, применяемые для блокирования, описаны в таблице ниже:

Атрибуты блокирования
Атрибут Описание
lockAllAttributesExcept

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

lockAllElementsExcept

Предотвращает изменения, вносимые на более низких уровнях, для дочерних элементов, исключая указанные

lockAttributes

Предотвращает изменения, вносимые на более низких уровнях, для указанных атрибутов

lockElements

Предотвращает изменения, вносимые на более низких уровнях, для указанных дочерних элементов

lockItem

Предотвращает изменения, вносимые на более низких уровнях, для элемента, а также для всех его атрибутов и дочерних элементов

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

...
  <customDefaults>
    <newUserDefaults city="Москва" country="Россия" language="Русский" regionCode="77"
                     lockAllAttributesExcept="language"/>
    <colors default="GRE" lockItem="true">
      <add code="GRE" value="green" name="Зеленый" />
      <add code="BLU" value="blue" name="Синий" />
      <add code="RED" value="red" name="Красный" />
    </colors>
  </customDefaults>
...

Мы применили атрибут lockAllAttributesExcept к разделу newUserDefaults и указали, что на более низких уровнях в иерархии конфигурации может изменяться только атрибут language. Поскольку мы имеем дело с файлом Web.config уровня приложения, блокировка касается элементов location и файлов Web.config уровня папок. К разделу colors применен атрибут lockItem, который предотвратит внесение изменений в атрибуты и дочерние элементы для элемента colors.

Чтобы продемонстрировать воздействие перечисленных выше атрибутов, мы модифицировали элемент location в файле Web.config, как показано в примере ниже:

...
  <location path="Admin/FolderForm.aspx">
    <customDefaults>
       <newUserDefaults language="Французский" regionCode="2" />
      <colors default="BLU">
        <add code="ORA" value="orange" name="апельсиновый" />
      </colors>
    </customDefaults>
  </location>
...

Элемент location нарушает обе блокировки. В элементе newUserDefaults определен атрибут regionCode, а внутри элемента colors присутствует дочерний элемент add. Блокировка не оценивается до тех пор, пока не будет запрошено определение элемента, к которому она применена, находящееся на более низком уровне. Это означает, что проблемы в элементе location не обнаружатся до тех пор, пока внутри веб-формы Admin\FolderForm.aspx не будут запрошены элементы newUserDefaults или colors (и даже тогда сообщается о наличии проблем блокировки в запрошенном разделе).

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

В примере ниже приведена модифицированная версия файла отделенного кода Admin\FolderForm.aspx.cs с обращением к обоим разделам конфигурации, к которым применены блокировки:

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

namespace ConfigFiles.Admin
{
    public partial class FolderForm : System.Web.UI.Page
    {
        public IEnumerable<string> GetConfig()
        {
            NewUserDefaultsSection defaults
                = (NewUserDefaultsSection)WebConfigurationManager
                      .GetSection("customDefaults/newUserDefaults");
            yield return string.Format("Значения: {0}, {1}, {2}, {3}<br><br>",
                defaults.City, defaults.Country, defaults.Language, defaults.Region);

            Configuration config
                = WebConfigurationManager.OpenWebConfiguration(Request.Path);

            UserAndPlaceSectiongroup group
                = (UserAndPlaceSectiongroup)config.SectionGroups["customDefaults"];
            ColorSection section = group.Colors;

            Color defaultColor = section.Colors[section.Default];
            yield return string.Format(
                @"Цвет по умолчанию - <span style=""color:white;background:{0}"">{1}</span><br><br>",
                defaultColor.Value, defaultColor.Name);

            foreach (Color color in section.Colors)
                yield return string.Format(
                @"Цвет - <span style=""color:white;background:{0}"">{1}</span><br><br>",
                color.Value, color.Name);
        }
    }
}

Код в примере предназначен только для демонстрации результатов нарушения блокировки, определенной в разделе конфигурации на более высоком уровне, которые можно увидеть, запустив приложение и запросив веб-форму Admin/FolderForm.aspx:

Сообщение об ошибке, отображаемое при нарушении блокировки в конфигурации

Если приложение запускается в отладчике Visual Studio, сообщение об ошибке, показанное на рисунке не отобразится, т.к. отладчик перехватит исключение и остановит выполнение кода. Нажатие клавиши <F5> приведет к возобновлению выполнения и отображению этого сообщения об ошибке.

Сообщение об ошибке, отображаемое в браузере, содержит подробные сведения о возникшей проблеме:

Сообщение об ошибке синтаксического анализатора: 
Атрибут 'regionCode' был заблокирован в конфигурации высшего уровня.

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

Однако когда дело доходит до разделов конфигурации в виде коллекций, вариантов становится больше. В примере ниже приведено содержимое файла Web.config с модифицированной блокировкой:

...
  <customDefaults>
    <newUserDefaults city="Москва" country="Россия" language="Русский" regionCode="77"/>
    <colors default="GRE" lockElements="clear,remove">
      <add code="GRE" value="green" name="Зеленый" />
      <add code="BLU" value="blue" name="Синий" />
      <add code="RED" value="red" name="Красный" />
    </colors>
  </customDefaults>
...

Мы удалили атрибут lock из раздела newUserDefaults, а также изменили блокировку для раздела colors. С помощью атрибута lockElements мы запретили изменение дочерних элементов remove и clear. Это разрешает добавление новых элементов в конфигурациях более низкого уровня, но запрещает удаление существующих элементов:

Отмена блокировки

Мы часто применяем такой прием, чтобы предохранить ряд ключевых значений, от которых зависит код. Он позволяет командам работать над периферийными частями приложения, добавляя все, что им необходимо.

Установив атрибут allowOverride в false, можно предотвратить переопределение контента элементов location в конфигурациях более низкого уровня. Мы предпочитаем использовать блокирование разделов конфигурации, т.к. оно обладает высокой степенью детализации. Чтобы предотвратить определение разделов в конфигурациях, специфичных для папок, следует применять атрибут allowDefinition в элементе section.

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