Скачать исходный код |
Конфигурации сборки (build configurations) обеспечивают хранение нескольких версий настроек для солюшена и проектов. Создание новой конфигурации будет необходимым шагом для работы с несколькими окружениями и версиями релиза.
Для начала рассмотрим, что такое конфигурация сборки на уровне проекта и на уровне солюшена. Потом создадим свою конфигурацию и config-файлы для нее.
Что такое конфигурация Debug и Release
При создании проекта в Visual Studio по-умолчанию создается две конфигурации: Debug и Release. Многие знают, что при заливке на боевой сервер лучше собирать в Release, а для локальной работы подойдет Debug. Предлагаю детально посмотреть, что такое конфигурации и как они влияют на артефакты проекта.
Конфигурация сборки в проекте
Откроем файл проекта и посмотрим, как влияет выбранная конфигурация на сборку проекта.
MvcApplication.csproj:
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <DebugSymbols>true</DebugSymbols> <DebugType>full</DebugType> <Optimize>false</Optimize> <OutputPath>bin\</OutputPath> <DefineConstants>DEBUG;TRACE</DefineConstants> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> <DebugType>pdbonly</DebugType> <Optimize>true</Optimize> <OutputPath>bin\</OutputPath> <DefineConstants>TRACE</DefineConstants> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> </PropertyGroup>
Каждая группа свойств выставляется в зависимости от конфигурациии (Debug, Release,...) и платформы (AnyCPU, x64,...): Condition=" '$(Configuration)|$(Platform)' == ....
Свойства DebugSymbols, Optimize и другие в дальнейшем буду параметрами компиляции проекта. Задача по сборке проекта вызывается в файле Microsoft.CSharp.targets:
<Csc Condition=" '%(_CoreCompileResourceInputs.WithCulture)' != 'true' " AdditionalLibPaths="$(AdditionalLibPaths)" AddModules="@(AddModules)" AllowUnsafeBlocks="$(AllowUnsafeBlocks)" ApplicationConfiguration="$(AppConfigForCompiler)" BaseAddress="$(BaseAddress)" CheckForOverflowUnderflow="$(CheckForOverflowUnderflow)" CodePage="$(CodePage)" DebugType="$(DebugType)" DefineConstants="$(DefineConstants)" DelaySign="$(DelaySign)" DisabledWarnings="$(NoWarn)" DocumentationFile="@(DocFileItem)" EmitDebugInformation="$(DebugSymbols)" EnvironmentVariables="$(CscEnvironment)" ErrorEndLocation="$(ErrorEndLocation)" ErrorReport="$(ErrorReport)" FileAlignment="$(FileAlignment)" GenerateFullPaths="$(GenerateFullPaths)" HighEntropyVA="$(HighEntropyVA)" KeyContainer="$(KeyContainerName)" KeyFile="$(KeyOriginatorFile)" LangVersion="$(LangVersion)" LinkResources="@(LinkResource)" MainEntryPoint="$(StartupObject)" ModuleAssemblyName="$(ModuleAssemblyName)" NoConfig="true" NoLogo="$(NoLogo)" NoStandardLib="$(NoCompilerStandardLib)" NoWin32Manifest="$(NoWin32Manifest)" Optimize="$(Optimize)" OutputAssembly="@(IntermediateAssembly)" PdbFile="$(PdbFile)" Platform="$(PlatformTarget)" Prefer32Bit="$(Prefer32Bit)" PreferredUILang="$(PreferredUILang)" References="@(ReferencePath)" Resources="@(_CoreCompileResourceInputs);@(CompiledLicenseFile)" ResponseFiles="$(CompilerResponseFile)" Sources="@(Compile)" SubsystemVersion="$(SubsystemVersion)" TargetType="$(OutputType)" ToolExe="$(CscToolExe)" ToolPath="$(CscToolPath)" TreatWarningsAsErrors="$(TreatWarningsAsErrors)" UseHostCompilerIfAvailable="$(UseHostCompilerIfAvailable)" Utf8Output="$(Utf8Output)" WarningLevel="$(WarningLevel)" WarningsAsErrors="$(WarningsAsErrors)" WarningsNotAsErrors="$(WarningsNotAsErrors)" Win32Icon="$(ApplicationIcon)" Win32Manifest="$(Win32Manifest)" Win32Resource="$(Win32Resource)" />
Задача Csc является стандартной и фактически вызывает компилятор csc.exe. Свойства задачи будут переданы в командную строку компилятора.
Мы увидели, что конфигурация сборки (build configuration) определяет набор параметров для компиляции проекта (возможно еще какие-то свойства). Например, в конфигурации Debug свойство Optimize выставлено в false, а в Release оно выставлено в true. Это, в итоге, приводит к тому, что компилятору передается Optimize="$(Optimize)" и мы получаем оптимизированный код в Release и неоптимизированный в Debug.
Управление конфигурацией проекта через интерфейс
Настройки, которые мы видим в файле проекта, отражены во вкладке Project Properties. Для примера я поменял несколько настроек для конфигурации Debug:
Секция свойств Debug в файле проекта отражает изменения, которые мы сделали в интерфейсе, через выставление соответствующих свойств:
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <DebugSymbols>true</DebugSymbols> <DebugType>full</DebugType> <Optimize>true</Optimize> <OutputPath>bin\</OutputPath> <DefineConstants>DEBUG</DefineConstants> <ErrorReport>prompt</ErrorReport> <WarningLevel>3</WarningLevel> <AllowUnsafeBlocks>true</AllowUnsafeBlocks> <TreatWarningsAsErrors>true</TreatWarningsAsErrors> <PlatformTarget>x86</PlatformTarget> </PropertyGroup>
Для более точной настройки конфигурации рекомендую делать изменения внучную прямо в XML-код файла проекта, т.к. интерфейс имеет очень ограниченный набор свойств. Вам может понадобится определить/переопределить свойства для сборки, добавить файлы для компиляции/настройки проекта и т.п.
Конфигурация сборки в солюшене
На уровне солюшена хранится список проектов, активные конфигураци и информация обо всех конфигурациях по каждому проекту.
MvcApplication.sln:
... Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MvcApplication", "MvcApplication\MvcApplication.csproj", "{BB24DDE3-EB20-47A9-8A70-CFCCAA1613AD}" EndProject ... Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MvcApplicationNumberTwo", "MvcApplicationNumberTwo\MvcApplicationNumberTwo.csproj", "{9622301F-9699-482D-9394-DF0B05B5CAB4}" EndProject ... Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {BB24DDE3-EB20-47A9-8A70-CFCCAA1613AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {BB24DDE3-EB20-47A9-8A70-CFCCAA1613AD}.Debug|Any CPU.Build.0 = Debug|Any CPU {BB24DDE3-EB20-47A9-8A70-CFCCAA1613AD}.Release|Any CPU.ActiveCfg = Release|Any CPU {BB24DDE3-EB20-47A9-8A70-CFCCAA1613AD}.Release|Any CPU.Build.0 = Release|Any CPU {9622301F-9699-482D-9394-DF0B05B5CAB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {9622301F-9699-482D-9394-DF0B05B5CAB4}.Debug|Any CPU.Build.0 = Debug|Any CPU {9622301F-9699-482D-9394-DF0B05B5CAB4}.Release|Any CPU.ActiveCfg = Release|Any CPU {9622301F-9699-482D-9394-DF0B05B5CAB4}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection ...
Настройку этой секции можно делать прямо в файле солюшена, либо через интерфейс студии:
Более подробно о секциях файла солюшена и его взаимодействии с файлами проектов можно прочитать в MSDN:
Создание новой конфигурации
В реальном проекте обычно не хватает стандартных конфигураций, т.к. есть несколько окружений (например, тестовое и preproduction), для которых нужно особенным образом настроить сборку проекта и выставить свои строки подключения к базе данных, настроить SMTP, поменять ссылки к внешним сервисам и т.п.
Создать новую конфигурацию можно вручную, добавив нужный код в файл .sln и в файлы проектов, где это необходимо. Для простоты мы рассмотрим, как это делается через интерфейс Visual Studio. Будем создавать конфигурацию для UAT (название может быть произвольным, но должно быть уникальным):
В окне New Solution Configuration стоит обратить внимание на два поля:
— Create new project configurations
Если опция выбрана, то после нажатия Ок в каждом проекте, который есть в солюшене, будет создана секция типа:
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'UAT|AnyCPU'"> <PropertyGroup>
— Copy Settings from
Если из возможных вариантов мы выбираем <Empty>, то в проектах добавляется только:
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'UAT|AnyCPU'"> <OutputPath>bin\</OutputPath> <PropertyGroup>
Если из возможных вариантов мы выбираем существующую конфигурацию, то в каждом проекте создается новая секция свойств, которая копирует все свойства из выбранной конфигурации именно этого проекта:
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'UAT|AnyCPU'"> <DebugSymbols>true</DebugSymbols> <OutputPath>bin\</OutputPath> <DefineConstants>DEBUG</DefineConstants> <AllowUnsafeBlocks>true</AllowUnsafeBlocks> </PropertyGroup>
Создание config-файлов для новой конфигурации
В данный момент в проектах у нас есть файлы Web.config, Web.Debug.config и Web.Release.config. Мы создали новую конфигурацию UAT и нам надо добавить файл Web.UAT.config, чтобы описать там трансформации для UAT-сервера.
Мы можем явно создать нужный файл и поправить XML-код проекта. Перед тем, как лезть в код и вручную вносить изменения разберемся, что мы должны изменить. Через интерфейс Visual Studio выбираем Web.config, к который хотим добавить трансформацию для UAT, щелкаем правой кнопкой и нажимаем Add Config Transform:
Visual Studio создала файл Web.UAT.config и добавила в XML-код проекта:
<None Include="Web.UAT.config"> <DependentUpon>Web.config</DependentUpon> </None>
После добавления новых файлов конфигурации мы должны увидеть:
Нам осталось написать нужные трансформации для UAT в файле Web.UAT.config, как мы делали в статье Continuous Integration: Трансформация Web.config. Во время сборки проекта, с выбранной конфигурацией UAT, трансформация будет автоматически применена к файлу Web.config за счет:
... <Target Name="AfterBuild"> <TransformXml Source="Web.config" Transform="Web.$(Configuration).config" Destination="Web.config" StackTrace="true" /> </Target> ...
Итоги
Мы рассмотрели, что такое конфигурации сборки проекта и как создавать свою собстенную конфигурацию. После создания свой конфигурации мы можем создавать для нее config-файлы и записывать в них нужные трансформации.
Статья из серии Continuous Integration: Работа с Config-файлами:
Комментариев нет:
Отправить комментарий