Общие сведения о процессе сборки

Джейсон Ли

В этом разделе представлено пошаговое руководство по процессу сборки и развертывания корпоративного уровня. Подход, описанный в этом разделе, использует пользовательские файлы проекта Microsoft Build Engine (MSBuild) для обеспечения точного управления каждым аспектом процесса. В файлах проекта пользовательские целевые объекты MSBuild используются для запуска служебных программ развертывания, таких как средство веб-развертывания служб IIS (MSDeploy.exe) и служебная программа развертывания базы данных VSDBCMD.exe.

Примечание

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

Этот раздел является частью серии учебников, основанных на требованиях к корпоративному развертыванию вымышленной компании Fabrikam, Inc. В этой серии руководств используется пример решения диспетчера контактов для представления веб-приложения с реалистичным уровнем сложности, включая приложение ASP.NET MVC 3, службу Windows Communication Foundation (WCF) и проект базы данных.

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

Общие сведения о сборке и развертывании

В решении Диспетчера контактов три файла управляют процессом сборки и развертывания:

  • Универсальный файл проекта (Publish.proj). Он содержит инструкции по сборке и развертыванию, которые не изменяются между целевыми средами.
  • Файл проекта для конкретной среды (Env-Dev.proj). Он содержит параметры сборки и развертывания, относящиеся к определенной целевой среде. Например, можно использовать файл Env-Dev.proj для предоставления параметров для среды разработки или тестирования, а также создать альтернативный файл с именем Env-Stage.proj для предоставления параметров промежуточной среды.
  • Командный файл (Publish-Dev.cmd). Содержит команду MSBuild.exe, которая указывает, какие файлы проекта необходимо выполнить. Вы можете создать командный файл для каждой целевой среды, где каждый файл содержит команду MSBuild.exe, которая указывает отдельный файл проекта для конкретной среды. Это позволяет разработчику выполнить развертывание в разных средах, просто запустив соответствующий командный файл.

В примере решения эти три файла находятся в папке Опубликовать решение.

В примере решения можно найти три файла в папке Решения Публикация.

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

Как выглядит процесс сборки и развертывания на высоком уровне.

Первое, что происходит, это то, что два файла проекта , один из которых содержит универсальные инструкции по сборке и развертыванию, а второй содержит параметры среды, объединяются в один файл проекта. Затем MSBuild выполняет инструкции в файле проекта. Он создает каждый из проектов в решении, используя файл проекта для каждого проекта. Затем он обращается к другим средствам, таким как веб-развертывание (MSDeploy.exe) и служебная программа VSDBCMD, для развертывания веб-содержимого и баз данных в целевой среде.

От начала до конца процесс сборки и развертывания выполняет следующие задачи:

  1. Он удаляет содержимое выходного каталога при подготовке к новой сборке.

  2. Он выполняет сборку каждого проекта в решении:

    1. Для веб-проектов (в данном случае веб-приложения ASP.NET MVC и веб-службы WCF) процесс сборки создает пакет веб-развертывания для каждого проекта.
    2. Для проектов баз данных процесс сборки создает манифест развертывания (файл deploymanifest) для каждого проекта.
  3. Она использует служебную программу VSDBCMD.exe для развертывания каждого проекта базы данных в решении, используя различные свойства из файлов проекта ( целевую строку подключения и имя базы данных) вместе с файлом .deploymanifest.

  4. Она использует служебную программу MSDeploy.exe для развертывания каждого веб-проекта в решении, используя различные свойства из файлов проекта для управления процессом развертывания.

Пример решения можно использовать для более подробной трассировки этого процесса.

Примечание

Инструкции по настройке файлов проекта для конкретной среды для собственных серверных сред см. в разделе Настройка свойств развертывания для целевой среды.

Вызов процесса сборки и развертывания

Чтобы развернуть решение Диспетчера контактов в тестовой среде разработчика, разработчик запускает командный файл Publish-Dev.cmd . При этом вызывается MSBuild.exe, указывая Publish.proj в качестве файла проекта для выполнения и Env-Dev.proj в качестве значения параметра.

msbuild.exe Publish.proj /fl /p:TargetEnvPropsFile=EnvConfig\Env-Dev.proj

Примечание

Параметр /fl (сокращение от /fileLogger) записывает выходные данные сборки в файл с именем msbuild.log в текущем каталоге. Дополнительные сведения см. в справочнике по командной строке MSBuild.

На этом этапе MSBuild запускается, загружает файл Publish.proj и начинает обработку инструкций в нем. Первая инструкция указывает MSBuild на импорт файла проекта, указанного параметром TargetEnvPropsFile .

<Import Project="$(TargetEnvPropsFile)" />

Параметр TargetEnvPropsFile указывает файл Env-Dev.proj , поэтому MSBuild объединяет содержимое файла Env-Dev.proj с файлом Publish.proj .

Следующие элементы, которые MSBuild встречает в объединенном файле проекта, — это группы свойств. Свойства обрабатываются в том порядке, в котором они отображаются в файле. MSBuild создает пару "ключ-значение" для каждого свойства при условии, что выполняются все указанные условия. Свойства, определенные далее в файле, перезаписывают все свойства с тем же именем, определенным ранее в файле. Например, рассмотрим свойства OutputRoot .

<OutputRoot Condition=" '$(OutputRoot)'=='' ">..\Publish\Out\</OutputRoot>
<OutputRoot Condition=" '$(BuildingInTeamBuild)'=='true' ">$(OutDir)</OutputRoot>

Когда MSBuild обрабатывает первый элемент OutputRoot , предоставляя параметр с аналогичным именем, он устанавливает для свойства OutputRoot значение .. \Publish\Out. При обнаружении второго элемента OutputRoot , если условие принимает значение true, оно перезапишет значение свойства OutputRoot значением параметра OutDir .

Следующий элемент, встречающийся в MSBuild, — это отдельная группа элементов, содержащая элемент с именем ProjectsToBuild.

<ItemGroup>
   <ProjectsToBuild Include="$(SourceRoot)ContactManager-WCF.sln"/>
</ItemGroup>

MSBuild обрабатывает эту инструкцию, создавая список элементов с именем ProjectsToBuild. В этом случае список элементов содержит одно значение — путь и имя файла решения.

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

<Project ToolsVersion="4.0" 
         DefaultTargets="FullPublish" 
         xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

Это указывает MSBuild вызвать целевой объект FullPublish , если целевые объекты не указаны при вызове MSBuild.exe. Целевой объект FullPublish не содержит никаких задач; Вместо этого он просто задает список зависимостей.

<PropertyGroup>   
  <FullPublishDependsOn>
     Clean;
     BuildProjects;      
     GatherPackagesForPublishing;
     PublishDbPackages;
     PublishWebPackages;
  </FullPublishDependsOn>
</PropertyGroup>
<Target Name="FullPublish" DependsOnTargets="$(FullPublishDependsOn)" />

Эта зависимость сообщает MSBuild, что для выполнения целевого объекта FullPublish необходимо вызвать этот список целевых объектов в указанном порядке:

  1. Он должен вызвать целевой объект Clean .
  2. Он должен вызывать целевой объект BuildProjects .
  3. Он должен вызывать целевой объект GatherPackagesForPublishing .
  4. Он должен вызывать целевой объект PublishDbPackages .
  5. Он должен вызывать целевой объект PublishWebPackages .

Чистый целевой объект

Целевой объект Clean по сути удаляет выходной каталог и все его содержимое в качестве подготовки к новой сборке.

<Target Name="Clean" Condition=" '$(BuildingInTeamBuild)'!='true' ">
  <Message Text="Cleaning up the output directory [$(OutputRoot)]"/>
  <ItemGroup>
     <_FilesToDelete Include="$(OutputRoot)**\*"/>
  </ItemGroup>
  <Delete Files="@(_FilesToDelete)"/>
  <RemoveDir Directories="$(OutputRoot)"/>
</Target>

Обратите внимание, что целевой объект содержит элемент ItemGroup . При определении свойств или элементов в элементе Target вы создаете динамические свойства и элементы. Другими словами, свойства или элементы не обрабатываются до выполнения целевого объекта. Выходной каталог может не существовать или содержать файлы до начала процесса сборки, поэтому вы не сможете создать список _FilesToDelete как статический элемент; Вам нужно дождаться выполнения. Таким образом, список создается как динамический элемент в целевом объекте.

Примечание

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

В сторону от динамических элементов целевой объект Clean довольно прост и использует встроенные задачи Message, Delete и RemoveDir для выполнения следующих задач:

  1. Отправьте сообщение в средство ведения журнала.
  2. Создайте список удаляемых файлов.
  3. Удалите файлы.
  4. Удалите выходной каталог.

Целевой объект BuildProjects

Целевой объект BuildProjects в основном выполняет сборку всех проектов в примере решения.

<Target Name="BuildProjects" Condition=" '$(BuildingInTeamBuild)'!='true' ">
   <MSBuild Projects="@(ProjectsToBuild)"
            Properties="OutDir=$(OutputRoot);
                        Configuration=$(Configuration);
                        DeployOnBuild=true;
                        DeployTarget=Package"
            Targets="Build" />
  </Target>

Этот целевой объект был подробно описан в предыдущем разделе Основные сведения о файле проекта, чтобы проиллюстрировать, как задачи и целевые объекты ссылаться на свойства и элементы. На этом этапе вас в основном интересует задача MSBuild . Эту задачу можно использовать для сборки нескольких проектов. Задача не создает новый экземпляр MSBuild.exe; он использует текущий запущенный экземпляр для сборки каждого проекта. Основные моменты, представляющие интерес в этом примере, — это свойства развертывания:

  • Свойство DeployOnBuild указывает MSBuild выполнять все инструкции по развертыванию в параметрах проекта после завершения сборки каждого проекта.
  • Свойство DeployTarget определяет целевой объект, который требуется вызвать после сборки проекта. В этом случае целевой объект "Пакет" создает выходные данные проекта в развертываемый веб-пакет.

Примечание

Целевой объект пакета вызывает конвейер веб-публикации (WPP), который обеспечивает интеграцию между MSBuild и веб-развертыванием. Если вы хотите просмотреть встроенные целевые объекты, которые предоставляет WPP, просмотрите файл Microsoft.Web.Publishing.targets в папке %PROGRAMFILES(x86)%\MSBuild\Microsoft\VisualStudio\v10.0\Web.

Целевой объект GatherPackagesForPublishing

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

<Target Name="GatherPackagesForPublishing">
   <ItemGroup>
      <PublishPackages 
         Include="$(_ContactManagerDest)ContactManager.Mvc.deploy.cmd">
         <WebPackage>true</WebPackage>
         <!-- More item metadata -->  
      </PublishPackages>
      <PublishPackages 
         Include="$(_ContactManagerSvcDest)ContactManager.Service.deploy.cmd">
         <WebPackage>true</WebPackage>
         <!-- More item metadata -->
      </PublishPackages>
      <DbPublishPackages Include="$(_DbDeployManifestPath)">
         <DbPackage>true</DbPackage>
         <!-- More item metadata -->
      </DbPublishPackages>
   </ItemGroup>
</Target>

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

Элементы не используются в этом целевом объекте— он просто создает элементы и метаданные, связанные с каждым значением элемента. После обработки этих элементов элемент PublishPackages будет содержать два значения: путь к файлу ContactManager.Mvc.deploy.cmd и путь к файлу ContactManager.Service.deploy.cmd . Веб-развертывание создает эти файлы как часть веб-пакета для каждого проекта, и это файлы, которые необходимо вызвать на целевом сервере для развертывания пакетов. Если открыть один из этих файлов, вы увидите команду MSDeploy.exe с различными значениями параметров сборки.

Элемент DbPublishPackages будет содержать одно значение — путь к файлу ContactManager.Database.deploymanifest .

Примечание

Файл .deploymanifest создается при сборке проекта базы данных и использует ту же схему, что и файл проекта MSBuild. Он содержит все сведения, необходимые для развертывания базы данных, включая расположение схемы базы данных (DBSCHEMA) и сведения о скриптах перед развертыванием и после развертывания. Дополнительные сведения см. в статье Общие сведения о сборке и развертывании базы данных.

Дополнительные сведения о создании и использовании пакетов развертывания и манифестов развертывания базы данных см. в статье Создание и упаковка проектов веб-приложений и Развертывание проектов баз данных.

Целевой объект PublishDbPackages

Вкратце говоря, целевой объект PublishDbPackages вызывает служебную программу VSDBCMD для развертывания базы данных ContactManager в целевой среде. Настройка развертывания базы данных включает в себя множество решений и нюансов, и вы узнаете больше об этом в статье Развертывание проектов баз данных и Настройка развертываний баз данных для нескольких сред. В этом разделе мы сосредоточимся на том, как на самом деле работает этот целевой объект.

Во-первых, обратите внимание, что открывающий тег содержит атрибут Outputs .

<Target Name="PublishDbPackages" Outputs="%(DbPublishPackages.Identity)">

Это пример целевой пакетной обработки. В файлах проекта MSBuild пакетная обработка — это метод перебора коллекций. Значение атрибута Outputs"%(DbPublishPackages.Identity)" ссылается на свойство метаданных Identity списка элементов DbPublishPackages . Эта нотация Outputs=%(ItemList.ItemMetadataName) преобразуется как:

  • Разделите элементы в DbPublishPackages на пакеты элементов, которые содержат одно и то же значение метаданных identity .
  • Выполните целевой объект один раз для каждого пакета.

Примечание

Identity — это одно из встроенных значений метаданных , которое назначается каждому элементу при создании. Он ссылается на значение атрибута Include в элементе Item , другими словами, путь и имя файла элемента.

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

Аналогичная нотация отображается в свойстве _Cmd , которое создает команду VSDBCMD с соответствующими параметрами.

<_Cmd>"$(VsdbCmdExe)" 
   /a:Deploy 
   /cs:"%(DbPublishPackages.DatabaseConnectionString)" 
   /p:TargetDatabase=%(DbPublishPackages.TargetDatabase)             
   /manifest:"%(DbPublishPackages.FullPath)" 
   /script:"$(_CmDbScriptPath)" 
   $(_DbDeployOrScript)
</_Cmd>

В этом случае %(DbPublishPackages.DatabaseConnectionString), %(DbPublishPackages.TargetDatabase) и %(DbPublishPackages.FullPath) ссылаются на значения метаданных коллекции элементов DbPublishPackages . Свойство _Cmd используется задачей Exec , которая вызывает команду .

<Exec Command="$(_Cmd)"/>

В результате этой нотации задача Exec создаст пакеты на основе уникальных сочетаний значений метаданных DatabaseConnectionString, TargetDatabase и FullPath , и задача будет выполняться один раз для каждого пакета. Это пример пакетной обработки задач. Но так как пакетная обработка на целевом уровне уже разделила нашу коллекцию элементов на пакеты с одним элементом, задача Exec будет выполняться один раз и только один раз для каждой итерации целевого объекта. Другими словами, эта задача вызывает служебную программу VSDBCMD один раз для каждого пакета базы данных в решении.

Примечание

Дополнительные сведения о пакетной обработке целевых файлов и задач см. в разделах Пакетная обработка MSBuild, Метаданные элементов в целевой пакетной обработке и Метаданные элементов в пакетной обработке задач.

Целевой объект PublishWebPackages

К этому моменту вы уже вызвали целевой объект BuildProjects , который создает пакет веб-развертывания для каждого проекта в примере решения. Каждый пакет сопровождается файлом deploy.cmd , который содержит команды MSDeploy.exe, необходимые для развертывания пакета в целевой среде, и файлSetParameters.xml , в котором указаны необходимые сведения о целевой среде. Вы также вызвали целевой объект GatherPackagesForPublishing , который создает коллекцию элементов, содержащую интересующие вас файлы deploy.cmd . По сути, целевой объект PublishWebPackages выполняет следующие функции:

  • Он управляет файломSetParameters.xml для каждого пакета, чтобы включить правильные сведения для целевой среды с помощью задачи XmlPoke .
  • Он вызывает файл deploy.cmd для каждого пакета с помощью соответствующих параметров.

Как и целевой объект PublishDbPackages , целевой объект PublishWebPackages использует целевую пакетную обработку, чтобы гарантировать, что целевой объект выполняется один раз для каждого веб-пакета.

<Target Name="PublishWebPackages" Outputs="%(PublishPackages.Identity)">

В целевом объекте задача Exec используется для запуска файла deploy.cmd для каждого веб-пакета.

<PropertyGroup>
   <_Cmd>
      %(PublishPackages.FullPath) 
      $(_WhatifSwitch) 
      /M:$(MSDeployComputerName) 
      %(PublishPackages.AdditionalMSDeployParameters)
   </_Cmd>
</PropertyGroup>
<Exec Command="$(_Cmd)"/>

Дополнительные сведения о настройке развертывания веб-пакетов см. в статье Создание и упаковка проектов веб-приложений.

Заключение

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

Дополнительные материалы

Более подробные сведения о файлах проекта и WPP см. в статье Inside the Microsoft Build Engine: Using MSBuild and Team Foundation Build by Sayed Ibrahim Hashimi and William Bartholomew, ISBN: 978-0-7356-4524-0.