Pull to refresh

.NET-разработка: переключения между DEV и PROD-окружениями. Часть первая

Reading time 7 min
Views 15K

Введение


Разрабатывая и отлаживая проект в Visual Studio, вы, как правило, делаете это, компилируя код в Debug-конфигурации. На боевой же сервер проект выкладывается, откомпилированный в Release-конфигурации. И каждый проект рано или поздно разрастается настолько, что в нём появляется некий «отладочный» или «релизный» код — то есть, тот код, который должен работать только в одной из конфигураций. И если бы дело ограничивалось только кодом, то директива условной компиляции #if решала бы все проблемы. Но обычно за кодом ещё тянутся настройки, специфичные для каждой из конфигураций, а зачастую и разметка веб-страниц. В самом начале, когда такие проблемы только начинают появляться, и ещё не являются сильной головной болью, обычно используется банальное комментирование ненужных в конкретный момент строк с кодом/разметкой/настройками. Но это — Road To Hell в самом чистом виде. А вот о Stairway To Heaven я и хотел бы рассказать.



Когда я впервые столкнулся с такой проблемой и уже погряз в костылях из комментариев и наборов различных конфигурационных файлов, то в какой-то момент решил поинтересоваться чужим опытом, а также получше изучить возможности среды разработки и используемых инструментов. И внезапно выяснил, что все мои искусственные костыли являются абсолютно избыточными — проблема может быть решена стандартными средствами и без ухудшения читаемости кода. Итоги моего исследования я опишу в небольшом цикле статей, где рассмотрю и примеры проблем с окружением, и механизмы, с помощью которых весь код, настройки и html-разметку автоматически можно привести в нужный вид при публикации проекта. Речь при этом пойдёт о разработке ASP.NET MVC-приложений, как области, в которой я, в основном, и работаю. Однако, всё написанное будет применимо к любой .NET-разработке в Visual Studio.

Трансформация web.config-файла


В этой статье я начну с первого важного инструмента — с трансформации web.config-файла. Если вы до сих пор не знакомы с этой техникой, то данный раздел вам обязательно стоит прочесть.

Трансформация появилась вместе с Visual Studio 2010 и сразу же решила огромное количество проблем, связанных с разными настройками для DEV и PROD-окружения. При этом, правила, по которым выполняется трансформация, чрезвычайно простые и гибкие.

Вы наверняка замечали, что, начиная с VS 2010, файл web.config внезапно начал отображаться в дереве проекта как контейнер, внутри которого теперь лежат два новых файла web.release.config и web.debug.config. Это и есть файлы, в которых настраивается трансформация основного web.config-файла. Вы можете вообще не использовать эти два файла и работать с основным web.config, как с единственным, и это не повлечёт за собой никаких проблем. Но будет лучше постигнуть этот дзен, чтобы впоследствии практиковать его всегда и с умом.

Изучая, как работает трансформация, самое главное — чётко усвоить две главные вещи при её настройке:

1. Трансформация работает только при публикации (publish) проекта

2. Файлы web.debug.config и web.release.config не заменяют оригинальный web.config, а изменяют (трансформируют) его

Казалось бы, что первый пункт накладывает серьёзные ограничения на использование трансформации в разработке. И действительно, какой от неё может быть толк, когда вы разрабатываете проект, например, под IIS Express, то есть, без публикаций? Но на самом деле, это не проблема, однако я затрону этот момент позже.

Что касается второго пункта, то это обычная ошибка тех, кто впервые столкнулся с трансформацией, включая меня: сперва я решил, что при публикации происходит подмена файла web.config на соответствующий release/debug-файл. Разумеется, первая же публикация заставила меня прочесть мануал внимательно, потому что это работает совсем не так.

Работает же это следующим образом: в файлах трансформации указывается как именно должен быть изменён оригинальный web.config при публикации в соответствующей конфигурации. Не будем далеко ходить и рассмотрим стандартный пример. Автосоздаваемый файл web.release.config по умолчанию уже содержит одну стандартную директиву для трансформации. Вот его листинг (с удалёнными комментариями):

<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
    <system.web>
        <compilation xdt:Transform="RemoveAttributes(debug)" />
    </system.web>
</configuration>


Для начала, обратите внимание на ключевой момент: у элемента configuration определяется префикс xdt для неймспейса XML-Document-Transform. В этом неймспейсе объявлены два атрибута, с помощью которых и определяется трансформация: Locator и Transform. Атрибут Locator определяет, что именно вы хотите изменить в конфигурационном файле, а атрибут Transform указывает как вы хотите это сделать. В приведённом примере используется только Transform — его значение говорит нам, что нужно в элементе compilation оригинального файла web.config удалить атрибут debug (вместе с его значением, разумеется).

Справочно: атрибут debug элемента configuration/system.web/compilation отвечает за компиляцию asp.net-страниц. В создаваемом по умолчанию файле web.config значение этого атрибута обычно true, и это означает, что asp.net-страницы будут откомпилированы с добавлением отладочной информации. В Release-конфигурации (то есть, в конфигурации, в которой проект обычно компилируется для выкладывания в PROD) этого делать не нужно, и именно для этого в файл трансформации web.release.config по умолчанию вставлена команда для удаления этого атрибута. Обо всём этом я ещё упомяну подробнее, но позднее.

Вернёмся к нашему примеру. При публикации проекта в Release-конфигурации из финального web.config-файла будет убран атрибут debug в элементе configuration/system.web/compilation, причём, независимо от того, какое у него было значение и был ли он там вообще. Обратите внимание, что в примере отсутствует атрибут Locator, потому что трансформация явно задана для конкретного элемента config-файла. Но с помощью атрибута Locator можно более гибким способом указывать элементы web.config-файла для трансформации, в частности, используя XPath-выражения или задавая явное соответствие значений атрибутов. Вот ещё пример:

<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
    <appSettings>
        <add key="Setting1" value="SettingValue" xdt:Locator="Condition(@key='key1')" xdt:Transform="Replace"/>
   </appSettings>
</configuration>


В этом примере в исходном web.config будет проведён поиск настройки с ключом key1 (это указано через XPath в Locator), и если такая будет найдена, то она будет полностью заменена

(значение Replace атрибута Transform) на настройку из файла с трансформацией. Значение Condition атрибута Locator содержит XPath-выражение, применяемое к тому элементу config-файла, в котором оно определено, при этом сам элемент автоматически становится текущим для XPath-выражения. Кроме Condition в атрибуте Locator можно указать значение XPath — он отличается только тем, что XPath-выражение будет рассмотрено в глобальном контексте.

Ещё пример:

<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
    <system.web>
        <customErrors mode="On" xdt:Transform="Insert">
            <error statusCode="404" redirect="/Error404" />
            <error statusCode="500" redirect="/Error500" />
        </customErrors>
    </system.web>
</configuration>


В этом примере мы добавляем в итоговый web.config целую секцию настроек customErrors (кстати, весьма полезная и часто используемая секция для настройки поведения веб-приложения в случае возникновения ошибки). Замечу, что, используя значение Insert атрибута Transform, мы предполагаем отсутствие этой секции в оригинальном web.config. Если же она там есть, то нам следует использовать Replace вместо Insert.

В итоге мы имеем мощный инструмент, с помощью которого мы можем на лету при публикации проекта изменять web.config-файл самыми разными способами, а именно: изменять, удалять или добавлять отдельные элементы либо атрибуты элементов (а также целые группы элементов) и менять значения любых атрибутов у любых элементов. Это позволяет нам избавиться от постоянного комментирования настроек в web.config-файле или регулярной его подмены на «тестовый»/«боевой» при отладке. Полный список значений атрибутов трансформации с примерами использования вы можете найти в MSDN.

Если говорить о реальном использовании трансформаций в моих проектах, то из всех настроек web.config-файла чаще всего затрагиваются следующие:

1. Connection Strings или, другими словами, все настройки подключения к базам данных. Это касается и самих connection string и настроек всех ORM-фреймворков.

2. Настройки секции appSettings. Все настройки переводятся из режима разработки/отладки в режим боевого использования.

3. Настройки обработки ошибок веб-приложения — секция /<system.web>/ в примере выше. При разработке и тестировании лично для меня предпочтительнее видеть все ошибки с текстом и stack trace сразу, а не быть перекинутым на красивую страницу-заглушку. Разумеется, для боевого приложения это неприемлемо.

4. Настройки trace/log/debug. Кроме упомянутой выше настройки /> из web.config вычищаются все настройки, связанные с отладкой и трейсом (либо оставляются, но выключаются). А настройки лога переводятся из параноидального режима в рабочий.

5. Настройки профилей кэширования веб-страниц. Http-кэширование страниц совершенно не нужно при отладке, поэтому профили кэширования в web.debug.config просто выключены через атрибут enabled=”false”. (Надеюсь, вы используете профили кэширования в атрибуте OutputCache?)

Разумеется, это не полный перечень — всё зависит от конкретного проекта. Но именно эти настройки затрагиваются трансформациями почти во всех случаях.

Что же касается разработки с использованием IIS Express, при которой публикации не происходят, то, как я уже говорил, это не является проблемой для использования трансформаций. Я довольно часто разрабатываю веб-приложения с использованием IIS Express (то есть, без публикации на реальном веб-сервере), и поступаю довольно просто: оригинальный web.config-файл содержит все необходимые настройки в DEV-варианте, а трансформации задаются только в web.release.config. То есть, оригинальный web.config, по сути, выполняет роль web.debug.config-файла.

Итак, Visual Studio даёт нам возможность гибко управлять работой приложения в DEV и PROD окружениях, не внедряясь при этом в код, вёрстку или настройки с различными костылями или заглушками. Если вы до сих пор ещё не владеете этой техникой, то этот пробел необходимо срочно закрыть. В следующих статьях — о минификации, бандлах, скриптах, DEBUG и как это правильно использовать.
Tags:
Hubs:
+3
Comments 18
Comments Comments 18

Articles