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

100

Получать конфигурационную информацию часто удобно программным образом, особенно при расширении конфигурации специальными элементами (что будет показано вскоре). Для доступа к конфигурационной информации используется класс WebConfigurationManager, который определен в пространстве имен System.Web.Configuration.

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

Методы и свойства класса WebConfigurationManager
Имя Описание
AppSettings

Возвращает коллекцию пар "ключ/значение", которые используются для определения простых параметров, специфичных для приложения

ConnectionStrings

Возвращает коллекцию объектов ConnectionStringSettings, описывающих строки подключения к базам данных

GetSection()

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

GetWebApplicationSection()

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

OpenWebConfiguration()

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

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

Работа с параметрами приложения

Параметры приложения - это пары "ключ/значение", и они представляют собой простейший способ расширения приложения специальными параметрами. В примере ниже демонстрируется добавление ряда параметров приложения в файл Web.config уровня приложения:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  
  <appSettings>
    <add key="defaultCity" value="Москва"/>
    <add key="defaultCountry" value="Россия"/>
    <add key="defaultLanguage" value="Русский"/>
  </appSettings>
  
  ...
</configuration>

Параметры приложения определяются в элементе appSettings, который находится внутри элемента configuration верхнего уровня. Элемент appSettings управляет коллекцией значений, и мы применяем элемент <add> для определения трех новых специальных свойств конфигурации: defaultCity, defaultCountry и defaultLanguage. В элементе <add> поддерживаются атрибуты key и value. Этими данными мы будем заполнять пользовательский профиль для нового пользователя.

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

Чтобы прочитать параметры приложения, мы обращаемся к свойству WebConfigurationManager.AppSettings, которое возвращает коллекцию, индексированную по ключу. Увидеть, как это работает, можно в примере ниже, в котором демонстрируется извлечение и отображение параметров приложения в файле отделенного кода Default.aspx.cs:

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

namespace ConfigFiles
{
    public partial class Default : System.Web.UI.Page
    {
        public IEnumerable<string> GetConfig()
        {
            foreach (string key in WebConfigurationManager.AppSettings)
            {
                yield return string.Format("{0} {1}", key,
                    WebConfigurationManager.AppSettings[key]);
            }
        }
    }
}

С помощью ключевого слова yield генерируются строковые значения для отображения имен и значений параметров приложения. Результат запуска приложения и запроса веб-формы Default.aspx показан на рисунке ниже:

Отображение параметров приложения посредством веб-формы Default.aspx

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

Переопределение параметров приложения

Параметры приложения объединяются, как и любые другие части конфигурации приложения. Это означает возможность применения элементов location или файлов Web.config уровня папок для корректировки параметров, связанных с разными частями приложения. Чтобы показать это в работе, мы добавили в проект новую папку под названием Admin и поместили в нее веб-форму по имени FolderForm.aspx с контентом, представленным в примере ниже:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="FolderForm.aspx.cs" 
   Inherits="ConfigFiles.Admin.FolderForm" %>

<!DOCTYPE html>
<html>
<head runat="server">
    <title></title>
</head>
<body>
    <h3>Это файл ~/Admin/FolderForm.aspx</h3>
    <asp:Repeater ID="Repeater1" runat="server" SelectMethod="GetConfig" ItemType="System.String">
        <HeaderTemplate>
            <ul>
        </HeaderTemplate>
        <FooterTemplate>
            </ul>
        </FooterTemplate>
        <ItemTemplate>
            <li><%# Item %></li>
        </ItemTemplate>
    </asp:Repeater>
</body>
</html>

Веб-форма содержит ту же самую разметку, что и файл Default.aspx, с добавленным элементом заголовка, который отображает название веб-формы. Содержимое файла отделенного кода Admin\FolderPage.aspx.cs приведено в примере ниже:

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

namespace ConfigFiles.Admin
{
    public partial class FolderForm : System.Web.UI.Page
    {
        public IEnumerable<string> GetConfig()
        {
            foreach (string key in WebConfigurationManager.AppSettings)
                yield return string.Format("{0} = {1}",
                key, WebConfigurationManager.AppSettings[key]);
        }
    }
}

В этом классе определен такой же метод GetConfig(), как и в файле Default.aspx.cs. (Конечно, существуют более эффективные способы работы с повторяющимся кодом и разметкой, такие как использование элемента управления, но в этой статье внимание сосредоточено на системе конфигурации, поэтому мы стремимся все упрощать.)

Чтобы продемонстрировать объединение параметров приложения, мы добавили в файл Web.config уровня приложения элемент location:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  
  ...

  <location path="Admin/FolderForm.aspx">
    <appSettings>
      <add key="defaultCity" value="Санкт-Петербург"/>
    </appSettings>
  </location>
</configuration>

Атрибут path элемента location установлен так, что он применяется только к новой веб-форме. Внутри элемента location определен элемент appSettings, в рамках которого используется элемент <add> для создания нового параметра и модификации значения одного из существующих параметров. Запустив приложение и запросив веб-форму Admin\FolderForm.aspx, можно увидеть результат:

Результат определения параметров приложения в элементе location

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

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

Работа со строками подключения

Свойство WebConfigurationManager.ConnectionStrings возвращает коллекцию объектов ConnectionStringSettings, каждый из которых представляет строку подключения. Возможность чтения строк подключения удобна, когда разрабатываемый код должен взаимодействовать напрямую с базой данных, а не использовать уровень абстракции, подобный Entity Framework (хотя строка подключения может понадобиться и при работе с EF, как будет показано ниже).

Чтобы продемонстрировать, как это работает, мы добавили в файл Web.config уровня приложения элемент connectionString, представленный в примере:

<?xml version="1.0" encoding="utf-8"?>
<configuration>

  <connectionStrings>
    <add name="defaultConnection" providerName="System.Data.SqlClient"
         connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=GameStore;Integrated Security=True"/>
  </connectionStrings>
  
  ...
</configuration>

Здесь применяется строка подключения из статьи, связанной с базой данных интернет-магазина GameStore.

Использование свойства WebConfigurationManager.ConnectionStrings можно видеть в примере ниже, в котором показаны изменения, внесенные в файл Default.aspx.cs:

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()
        {
            foreach (ConnectionStringSettings setting in 
                WebConfigurationManager.ConnectionStrings)
            {
                yield return string.Format("Name: <b>{0}</b><br>connectionString: <b>{1}</b><br><br>",
                    setting.Name, setting.ConnectionString);
            }
        }
    }
}

Класс ConnectionStringsSettings находится в пространстве имен System.Configuration и определяет три свойства, которые описаны в таблице ниже:

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

Соответствует атрибуту name элемента add

ProviderName

Соответствует атрибуту providerName элемента add

ConnectionString

Соответствует атрибуту connectionString элемента add

Строки подключения трактуются как коллекция, поэтому набор объектов ConnectionStringSettings, возвращаемый свойством WebConfigurationManager.ConnectionStrings, является результатом последовательного применения элементов add, remove и clear на разных уровнях иерархии. На рисунке ниже представлен вывод, полученный после запуска приложения и запроса URL вида /Default.aspx:

Перечисление строк подключения, определенных в конфигурации
http://k>ci(ho5t38?J9/D«fautt.«px

На рисунке ниже отображаются три строки подключения. Причина в том, что файл Machine.config содержит следующие элементы:

...
<connectionStrings>
    <add name="LocalSqlServer" 
	    connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;
           AttachDBFilename=|DataDirectory|aspnetdb.mdf;User Instance=true"       
		providerName="System.Data.SqlClient"/>
    <add name="LocalMySqlServer" connectionString=""/>
</connectionStrings>
...

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

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

Мы предпочитаем с помощью элемента clear в файле Web.config уровня приложения удалять любые строки подключения, которые определены на более высоких уровнях:

<?xml version="1.0" encoding="utf-8"?>
<configuration>

  <connectionStrings>
    <clear />
    <add name="defaultConnection" providerName="System.Data.SqlClient"
         connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=GameStore;Integrated Security=True"/>
  </connectionStrings>
  
  ...
</configuration>

Соединение с базой данных с использованием строки подключения

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

<?xml version="1.0" encoding="utf-8"?>
<configuration>

  <connectionStrings>
    <clear />
    <add name="defaultConnection" providerName="System.Data.SqlClient"
         connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=GameStore;Integrated Security=True"/>
  </connectionStrings>
  
  <appSettings>
    <add key="dbConnectionString" value="defaultConnection"/>
    ...
  </appSettings>
  
  ...
</configuration>

В примере ниже мы извлекаем имя строки подключения из параметра приложения, применяем его для получения самой строки подключения и затем соединяемся заново с базой данных с помощью Entity Framework для выполнения запроса:

using System.Web.Configuration;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Data.Entity;

namespace ConfigFiles
{
    public class EFDbContext : DbContext
    {
        public EFDbContext(string connectionString) : base(connectionString)
        { }

        public DbSet<Game> Games { get; set; }
    }

    public class Game
    {
        public int GameId { get; set; }
        public string Name { get; set; }
    }

    public partial class Default : System.Web.UI.Page
    {
        public IEnumerable<string> GetConfig()
        {
            // Получить название строки подключения
            string csName = WebConfigurationManager.AppSettings["dbConnectionString"];

            foreach (string name in new EFDbContext(
                WebConfigurationManager.ConnectionStrings[csName].ConnectionString).Games.Select(g => g.Name))
            {
                yield return name;
            }
        }
    }
}

Обращение к параметру приложения производится по имени, а полученное значение затем используется для извлечения строки подключения также по имени.

Работоспособность этого примера зависит от наличия у вас подключения к тестовой базе данных GameStore и установки в проект пакета Entity Framework. На рисунке ниже показан результат, который получается при соблюдении этих условий:

Использование строк подключения для работы с базой данных

Коллекции, возвращаемые свойствами AppSettings и ConnectionStrings, позволяют получать значения по ключам. Именно так должны извлекаться и находиться строки подключения при работе с ними напрямую. В приведенном примере мы создаем соединение с базой данных с помощью класса поставщика DbContext и строки подключения из файла Web.config. Мы применяем его для отправки запроса к таблице Games базы данных GameStore. Пример предназначен только для демонстрации средств конфигурации.

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