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

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

Файл преобразования представляет собой XML-файл, в котором указаны изменения, которые требуется внести в файл Web.config. В файлах преобразования используются атрибуты XML, предназначенные специально для преобразования файлов Web.config для развертывания. В файлах применяются два атрибута: xdt:Transform и xdt:Locator.

Чтобы добавить новый файл преобразования, требуется добавить новую конфигурацию проекта.
NewConfig
Затем вызвать контекстное меню файла Web.config в Solution Explorer и выбрать пункт Add Config Transform. Будет добавлен файл Web.ConfigurationName.config.
NewWebConfig

Синтаксис преобразований

Атрибут Locator указывает элемент или набор элементов файла Web.config, которые требуется изменить. Атрибут Transform указывает, какие действия требуется произвести над элементами, найденными атрибутом Locator.

Корневой элемент файла преобразования должен указывать пространство имен XML-Document-Transform в открывающем теге, как это показано в примерах. Сами элементы Locator и Transform не воспроизводятся в развертываемом файле Web.config.

Преобразования применяются во время развертывания или сборки проекта в MsBuild, однако можно выполнить предварительный просмотр изменений в Visual Studio. В Solution Explorer, щелкнув правой кнопкой мыши файл преобразования (например, Web.Release.config), выберите Preview Transform. В левой части экрана будет отображаться текущий конфиг, а в правой — преобразованный.

Синтаксис атрибута Locator

Атрибут Condition

Задает выражение XPath, которое присоединяется к выражению XPath текущего элемента. Выделяются элементы, соответствующие суммарному значению XPath.

Locator="Condition(XPath expression)"

Атрибут Match

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

Locator="Match(разделенный запятыми список из одного или нескольких имен атрибутов)"

Атрибут XPath

Задает абсолютное выражение XPath, применяемое к файлу разработки Web.config. (В отличие от атрибута Condition задаваемое выражение не присоединяется к неявному выражению XPath, соответствующему текущему элементу).

Locator="XPath(XPath expression)"

Синтаксис атрибута Transform

Атрибут Replace

Заменяет выделенный элемент указанным в файле преобразования элементом. Если выделено более одного элемента, заменяется только первый элемент.

Transform="Replace"

Атрибут Insert

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

Transform="Insert"

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

<configuration xmlns:xdt="...">
<connectionStrings>
<add name="AWLT" connectionString="newstring"
providerName="newprovider"
xdt:Transform="Insert" />
</connectionStrings>
</configuration>

Атрибут InsertBefore

Вставляет элемент, заданный в XML-преобразования, непосредственно перед элементом, выделенным с помощью указанного выражения XPath. Выражение XPath должно быть абсолютным, поскольку оно применяется к файлу разработки Web.config в целом; это выражение не присоединяется к неявному выражению XPath текущего элемента.

Transform="InsertBefore(XPath expression)"

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

<configuration xmlns:xdt="...">
<authorization>
<allow roles="Admins"
xdt:Transform="InsertBefore(/configuration/system.web/authorization/deny[@users='*'])" />
</authorization>
</configuration>

Атрибут InsertAfter

Вставляет элемент, заданный в XML-преобразования, непосредственно после элемента, выделенного с помощью указанного выражения XPath. Выражение XPath должно быть абсолютным, поскольку оно применяется к файлу разработки Web.config в целом; это выражение не присоединяется к неявному выражению XPath текущего элемента.

Transform="InsertAfter(XPath expression)"

В следующем примере показано, как выделить элемент allow, который предоставляет доступ администраторам и вставляет после себя элемент deny, запрещающий доступ указанному пользователю.

<configuration xmlns:xdt="...">
 <authorization>
   <deny users="UserName"
     xdt:Transform="InsertAfter
       (/configuration/system.web/authorization/allow[@roles='Admins'])" />
 </authorization>
</configuration>

Атрибут Remove

Удаляет выбранный элемент. При выборе нескольких элементов удаляется первый элемент.

Transform="Remove"

Атрибут RemoveAll

Удаляет выбранные элементы.

Transform="RemoveAll"

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

<configuration xmlns:xdt="...">
 <connectionStrings>
   <add xdt:Transform="RemoveAll" />
 </connectionStrings>
</configuration>

Атрибут RemoveAttributes

Удаляет указанные атрибуты из выбранных элементов.

Transform="RemoveAttributes(разделенный запятыми список из одного или нескольких имен атрибутов)"

В следующем примере показано, как выделить все элементы compilation в файле разработки Web.config. (Поскольку в файле конфигурации может существовать только один элемент compilation, атрибут Locator задавать не требуется.) В развертываемом файле Web.config атрибуты debug и batch удаляются из элемента compilation.

<configuration xmlns:xdt="...">
 <compilation 
   xdt:Transform="RemoveAttributes(debug,batch)">
 </compilation>
</configuration>

Атрибут SetAttributes

Задает атрибутам выбранных элементов указанные значения. Атрибут преобразования Replace заменяет весь элемент, включая все его атрибуты. В отличие от него атрибут SetAttributes позволяет изменить выбранные атрибуты элемента. Если не указать, какие атрибуты следует заменить, то все атрибуты, присутствующие в элементе будут изменены.

Transform="SetAttributes(разделенный запятыми список из одного или нескольких имен атрибутов)"

В следующем примере показано, как выделить все элементы compilation в файле разработки Web.config. (Поскольку в файле конфигурации может существовать только один элемент compilation, атрибут Locator задавать не требуется.) В развертываемом файле Web.config для элемента compilation атрибуту batch присваивается значение false.

<configuration xmlns:xdt="...">
 <compilation 
   batch="false"
   xdt:Transform="SetAttributes(batch)">
 </compilation>
</configuration>

Трансформация

Трансформация и использование трансформированного Web.config на уровне среды разработки невозможна. Чтобы создать файл с примененными трансформациями, требуется использовать средства, предоставляемые MsBuild при помощи команд:

#Переходим в папку проекта
cd Path_Of_Project
#Собираем, применяя трансформацию
MsBuild Project_Name.csproj /t:TransformWebConfig /p:Configuration=Configuration_Name

Снимок1

Где OutputFile — путь до трансформированного файла.

Примеры преобразований

1. Строка подключения

Строка подключения на сервере, как правило, отличается от строки подключения на локальном компьютере. Следующий пример производит замену элемента add в секции connectionStrings с атрибутом name, равным testConnection.

<!-- Исходный текст -->
<connectionStrings>
   <add name="testConnection" providerName="System.Data.SqlClient" connectionString="data source=LocalServerSQLSERVER2012exp;initial catalog=test;persist security info=True;user id=admin;password=admin" />
</connectionStrings>
<!-- Код преобразования -->
<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
   <connectionStrings>
 <add name="testConnection"
     connectionString="data source=RemoteServerSQLSERVER2012exp;initial catalog=remote;persist security info=True;user id=admin;password=qwesjvfdlkja"
     xdt:Transform="Replace" xdt:Locator="Match(name)"/>
 </connectionStrings>
</configuration>
<!-- После преобразования -->
<connectionStrings>
 <add name="testConnection"
     connectionString="data source=RemoteServerSQLSERVER2012exp;initial catalog=remote;persist security info=True;user id=admin;password=qwesjvfdlkja"
  />
 </connectionStrings>

В приведенном примере значение Match(name) атрибута Locator указывает, что должен быть изменен только элемент add, имеющий то же имя (testConnection). Значение Replace атрибута Transform указывает, что в процессе развертывания должен быть заменен весь элемент add.

2. Социальные сети

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

<!-- Исходный текст -->
<appSettings>
   <add key="VKontakte.appId" value="999999999" />
   <add key="VKontakte.clientSecret" value="rkifFewo218afkjwrj" />
</appSettings>
<!-- Код преобразования -->
<appSettings>
   <add key="VKontakte.appId" value="88888888" 
        xdt:Transform="SetAttributes(value)"
        xdt:Locator="Match(key)"/>
   <add key="VKontakte.clientSecret" value="awdfkjUfewfbu224918" 
        xdt:Transform="SetAttributes(value)"
        xdt:Locator="Match(key)"/>
</appSettings>
<!-- После преобразования -->
<appSettings>
   <add key="VKontakte.appId" value="88888888" />
   <add key="VKontakte.clientSecret" value="awdfkjUfewfbu224918" />
</appSettings>

3. Добавление настроек SMTP

Использование в релизе настоящих почтовых ящиков

<!-- Исходный текст -->
<system.net>
   <mailSettings>
   </mailSettings>
   <defaultProxy enabled="true" />
</system.net>
<!-- Код преобразования -->
<system.net>
   <mailSettings>
     <smtp from="test@gmail.com"
           xdt:Locator="Match(from)"
           xdt:Transform="Insert" >
       <network enableSsl="true" host="smtp.gmail.com" port="587" userName="test@gmail.com" password="506484654" />
     </smtp>
   </mailSettings>
 </system.net>
<!-- После преобразования -->
<system.net>
   <mailSettings>
     <smtp from="test@gmail.com">
       <network enableSsl="true" host="smtp.gmail.com" port="587" userName="test@gmail.com password="506484654" />
     </smtp>
   </mailSettings>
</system.net>

С примерами можно ознакомиться в нашем тестовом приложении на GitHub.

В моей следующей статье рассмотрено шифрование данных в Web.config.

Источники

Практическое руководство на MSDN
Тема на форуме ASP.NET
Руководство по XPath
Синтаксис файла преобразований