Présentation du processus de génération

par Jason Lee

Cette rubrique fournit une procédure pas à pas d’un processus de génération et de déploiement à l’échelle de l’entreprise. L’approche décrite dans cette rubrique utilise des fichiers projet Microsoft Build Engine personnalisés (MSBuild) pour fournir un contrôle affiné sur chaque aspect du processus. Dans les fichiers projet, les cibles MSBuild personnalisées sont utilisées pour exécuter des utilitaires de déploiement tels que l’outil de déploiement web IIS (MSDeploy.exe) et l’utilitaire de déploiement de base de données VSDBCMD.exe.

Notes

La rubrique précédente, Présentation du fichier projet, décrit les composants clés d’un fichier projet MSBuild et introduit le concept de fractionnement des fichiers projet pour prendre en charge le déploiement dans plusieurs environnements cibles. Si vous n’êtes pas encore familiarisé avec ces concepts, consultez Présentation du fichier projet avant d’examiner cette rubrique.

Cette rubrique fait partie d’une série de tutoriels basés sur les exigences de déploiement d’entreprise d’une société fictive nommée Fabrikam, Inc. Cette série de tutoriels utilise un exemple de solution, la solution Contact Manager, pour représenter une application web avec un niveau de complexité réaliste, y compris une application MVC 3 ASP.NET, un service Windows Communication Foundation (WCF) et un projet de base de données.

La méthode de déploiement au cœur de ces didacticiels est basée sur l’approche de fichier projet fractionné décrite dans Présentation du fichier projet, dans laquelle le processus de génération est contrôlé par deux fichiers projet : l’un contenant des instructions de génération qui s’appliquent à chaque environnement de destination et l’autre contenant des paramètres de build et de déploiement spécifiques à l’environnement. Au moment de la génération, le fichier projet spécifique à l’environnement est fusionné dans le fichier projet indépendant de l’environnement pour former un ensemble complet d’instructions de build.

Vue d’ensemble de la génération et du déploiement

Dans la solution Gestionnaire de contacts, trois fichiers contrôlent le processus de génération et de déploiement :

  • Fichier projet universel (Publish.proj). Il contient des instructions de génération et de déploiement qui ne changent pas entre les environnements de destination.
  • Fichier projet spécifique à l’environnement (Env-Dev.proj). Il contient des paramètres de build et de déploiement spécifiques à un environnement de destination particulier. Par exemple, vous pouvez utiliser le fichier Env-Dev.proj pour fournir des paramètres pour un environnement de développeur ou de test et créer un autre fichier nommé Env-Stage.proj pour fournir des paramètres pour un environnement intermédiaire.
  • Un fichier de commandes (Publish-Dev.cmd). Il contient une commande MSBuild.exe qui spécifie les fichiers projet que vous souhaitez exécuter. Vous pouvez créer un fichier de commandes pour chaque environnement de destination, où chaque fichier contient une commande MSBuild.exe qui spécifie un autre fichier projet spécifique à l’environnement. Cela permet au développeur de déployer dans différents environnements simplement en exécutant le fichier de commandes approprié.

Dans l’exemple de solution, vous trouverez ces trois fichiers dans le dossier Publier la solution.

Dans l’exemple de solution, vous trouverez trois fichiers dans le dossier Publier la solution.

Avant d’examiner ces fichiers plus en détail, examinons le fonctionnement global du processus de génération lorsque vous utilisez cette approche. À un niveau général, le processus de génération et de déploiement ressemble à ceci :

À quoi ressemble le processus de génération et de déploiement à un niveau élevé.

La première chose qui se produit est que les deux fichiers projet, l’un contenant des instructions de génération et de déploiement universelles et l’autre contenant des paramètres spécifiques à l’environnement, sont fusionnés dans un seul fichier projet. MSBuild suit ensuite les instructions du fichier projet. Il génère chacun des projets de la solution, à l’aide du fichier projet pour chaque projet. Il appelle ensuite d’autres outils, tels que Web Deploy (MSDeploy.exe) et l’utilitaire VSDBCMD pour déployer votre contenu web et vos bases de données dans l’environnement cible.

Du début à la fin, le processus de génération et de déploiement effectue les tâches suivantes :

  1. Il supprime le contenu du répertoire de sortie, en préparation d’une nouvelle build.

  2. Il génère chaque projet dans la solution :

    1. Pour les projets web (dans ce cas, une application web MVC ASP.NET et un service web WCF), le processus de génération crée un package de déploiement web pour chaque projet.
    2. Pour les projets de base de données, le processus de génération crée un manifeste de déploiement (fichier .deploymanifest) pour chaque projet.
  3. Il utilise l’utilitaire VSDBCMD.exe pour déployer chaque projet de base de données dans la solution, à l’aide de différentes propriétés des fichiers projet (une chaîne de connexion cible et un nom de base de données) avec le fichier .deploymanifest.

  4. Il utilise l’utilitaire MSDeploy.exe pour déployer chaque projet web dans la solution, en utilisant différentes propriétés des fichiers projet pour contrôler le processus de déploiement.

Vous pouvez utiliser l’exemple de solution pour suivre ce processus plus en détail.

Notes

Pour obtenir des conseils sur la façon de personnaliser les fichiers projet spécifiques à l’environnement pour vos propres environnements serveurs, consultez Configurer les propriétés de déploiement pour un environnement cible.

Appel du processus de génération et de déploiement

Pour déployer la solution Contact Manager dans un environnement de test de développeur, le développeur exécute le fichier de commandes Publish-Dev.cmd . Cela appelle MSBuild.exe, en spécifiant Publish.proj comme fichier projet à exécuter et Env-Dev.proj comme valeur de paramètre.

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

Notes

Le commutateur /fl (abréviation de /fileLogger) consigne la sortie de build dans un fichier nommé msbuild.log dans le répertoire actif. Pour plus d’informations, consultez référence sur la ligne de commande MSBuild.

À ce stade, MSBuild commence à s’exécuter, charge le fichier Publish.proj et commence à traiter les instructions qu’il contient. La première instruction indique à MSBuild d’importer le fichier projet spécifié par le paramètre TargetEnvPropsFile .

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

Le paramètre TargetEnvPropsFile spécifie le fichier Env-Dev.proj , de sorte que MSBuild fusionne le contenu du fichier Env-Dev.proj dans le fichier Publish.proj .

Les éléments suivants rencontrés par MSBuild dans le fichier projet fusionné sont des groupes de propriétés. Les propriétés sont traitées dans l’ordre dans lequel elles apparaissent dans le fichier. MSBuild crée une paire clé-valeur pour chaque propriété, à condition que toutes les conditions spécifiées soient remplies. Les propriétés définies plus loin dans le fichier remplacent toutes les propriétés portant le même nom défini précédemment dans le fichier. Par exemple, considérez les propriétés OutputRoot .

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

Lorsque MSBuild traite le premier élément OutputRoot , en fournissant un paramètre nommé de même nom n’a pas été fourni, il définit la valeur de la propriété OutputRoot sur .. \Publish\Out. Lorsqu’il rencontre le deuxième élément OutputRoot , si la condition prend la valeur true, elle remplace la valeur de la propriété OutputRoot par la valeur du paramètre OutDir .

L’élément suivant rencontré par MSBuild est un groupe d’éléments unique, contenant un élément nommé ProjectsToBuild.

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

MSBuild traite cette instruction en créant une liste d’éléments nommée ProjectsToBuild. Dans ce cas, la liste d’éléments contient une seule valeur: le chemin d’accès et le nom du fichier de solution.

À ce stade, les éléments restants sont des cibles. Les cibles sont traitées différemment des propriétés et des éléments. Essentiellement, les cibles ne sont pas traitées, sauf si elles sont spécifiées explicitement par l’utilisateur ou appelées par une autre construction dans le fichier projet. Rappelez-vous que la balise Project d’ouverture inclut un attribut DefaultTargets .

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

Cela indique à MSBuild d’appeler la cible FullPublish , si les cibles ne sont pas spécifiées lorsque MSBuild.exe est appelé. La cible FullPublish ne contient aucune tâche ; au lieu de cela, il spécifie simplement une liste de dépendances.

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

Cette dépendance indique à MSBuild que pour exécuter la cible FullPublish , il doit appeler cette liste de cibles dans l’ordre fourni :

  1. Il doit appeler la cible Clean .
  2. Il doit appeler la cible BuildProjects .
  3. Il doit appeler la cible GatherPackagesForPublishing .
  4. Il doit appeler la cible PublishDbPackages .
  5. Il doit appeler la cible PublishWebPackages .

Cible propre

La cible Clean supprime essentiellement le répertoire de sortie et tout son contenu, comme préparation d’une nouvelle génération.

<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>

Notez que la cible inclut un élément ItemGroup . Lorsque vous définissez des propriétés ou des éléments dans un élément Target , vous créez des propriétés et des éléments dynamiques . En d’autres termes, les propriétés ou les éléments ne sont pas traités tant que la cible n’est pas exécutée. Le répertoire de sortie n’existe peut-être pas ou ne contient pas de fichiers tant que le processus de génération n’a pas commencé, de sorte que vous ne pouvez pas générer la liste _FilesToDelete en tant qu’élément statique ; vous devez attendre que l’exécution soit en cours. Par conséquent, vous générez la liste en tant qu’élément dynamique au sein de la cible.

Notes

Dans ce cas, étant donné que la cible Clean est la première à être exécutée, il n’est pas vraiment nécessaire d’utiliser un groupe d’éléments dynamique. Toutefois, il est recommandé d’utiliser des propriétés et des éléments dynamiques dans ce type de scénario, car vous souhaiterez peut-être exécuter des cibles dans un autre ordre à un moment donné.
Vous devez également éviter de déclarer des éléments qui ne seront jamais utilisés. Si vous avez des éléments qui ne seront utilisés que par une cible spécifique, envisagez de les placer à l’intérieur de la cible pour supprimer toute surcharge inutile sur le processus de génération.

À part les éléments dynamiques, la cible Nettoyer est assez simple et utilise les tâches intégrées Message, Supprimer et SupprimerDir pour :

  1. Envoyez un message à l’enregistreur d’événements.
  2. Créez une liste de fichiers à supprimer.
  3. Supprime les fichiers.
  4. Supprimez le répertoire de sortie.

La cible BuildProjects

La cible BuildProjects génère essentiellement tous les projets de l’exemple de solution.

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

Cette cible a été décrite en détail dans la rubrique précédente, Présentation du fichier projet, pour illustrer la façon dont les tâches et les cibles référencent les propriétés et les éléments. À ce stade, vous êtes principalement intéressé par la tâche MSBuild . Vous pouvez utiliser cette tâche pour générer plusieurs projets. La tâche ne crée pas de instance de MSBuild.exe ; elle utilise la instance en cours d’exécution pour générer chaque projet. Les principaux points d’intérêt de cet exemple sont les propriétés de déploiement :

  • La propriété DeployOnBuild indique à MSBuild d’exécuter toutes les instructions de déploiement dans les paramètres du projet une fois la génération de chaque projet terminée.
  • La propriété DeployTarget identifie la cible que vous souhaitez appeler une fois le projet généré. Dans ce cas, la cible de package génère la sortie du projet dans un package web déployable.

Notes

La cible de package appelle le pipeline de publication web (WPP), qui fournit l’intégration entre MSBuild et Web Deploy. Si vous souhaitez examiner les cibles intégrées que wpp fournit, passez en revue le fichier Microsoft.Web.Publishing.targets dans le dossier %PROGRAMFILES(x86)%\MSBuild\Microsoft\VisualStudio\v10.0\Web.

La cible GatherPackagesForPublishing

Si vous étudiez la cible GatherPackagesForPublishing , vous remarquerez qu’elle ne contient pas réellement de tâches. Au lieu de cela, il contient un seul groupe d’éléments qui définit trois éléments dynamiques.

<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>

Ces éléments font référence aux packages de déploiement qui ont été créés lors de l’exécution de la cible BuildProjects . Vous n’avez pas pu définir ces éléments de manière statique dans le fichier projet, car les fichiers auxquels les éléments font référence n’existent pas tant que la cible BuildProjects n’est pas exécutée. Au lieu de cela, les éléments doivent être définis dynamiquement dans une cible qui n’est appelée qu’après l’exécution de la cible BuildProjects .

Les éléments ne sont pas utilisés dans cette cible : cette cible génère simplement les éléments et les métadonnées associées à chaque valeur d’élément. Une fois ces éléments traités, l’élément PublishPackages contient deux valeurs: le chemin d’accès au fichier ContactManager.Mvc.deploy.cmd et le chemin d’accès au fichier ContactManager.Service.deploy.cmd . Web Deploy crée ces fichiers dans le cadre du package web pour chaque projet, et il s’agit des fichiers que vous devez appeler sur le serveur de destination pour déployer les packages. Si vous ouvrez l’un de ces fichiers, vous verrez essentiellement une commande MSDeploy.exe avec différentes valeurs de paramètre spécifiques à la build.

L’élément DbPublishPackages contient une valeur unique, le chemin d’accès au fichier ContactManager.Database.deploymanifest.

Notes

Un fichier .deploymanifest est généré lorsque vous générez un projet de base de données et utilise le même schéma qu’un fichier projet MSBuild. Il contient toutes les informations nécessaires au déploiement d’une base de données, notamment l’emplacement du schéma de base de données (.dbschema) et les détails des scripts de prédéploiement et de post-déploiement. Pour plus d’informations, consultez Vue d’ensemble de la création et du déploiement de bases de données.

Vous en apprendrez plus sur la façon dont les packages de déploiement et les manifestes de déploiement de base de données sont créés et utilisés dans Génération et empaquetage de projets d’application web et Déploiement de projets de base de données.

La cible PublishDbPackages

En bref, la cible PublishDbPackages appelle l’utilitaire VSDBCMD pour déployer la base de données ContactManager dans un environnement cible. La configuration du déploiement de base de données implique de nombreuses décisions et nuances, et vous en apprendrez davantage à ce sujet dans Déploiement de projets de base de données et personnalisation des déploiements de base de données pour plusieurs environnements. Dans cette rubrique, nous allons nous concentrer sur le fonctionnement réel de cette cible.

Tout d’abord, notez que la balise d’ouverture inclut un attribut Outputs .

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

Il s’agit d’un exemple de traitement par lot cible. Dans les fichiers projet MSBuild, le traitement par lots est une technique permettant d’itérer sur des collections. La valeur de l’attribut Outputs , « %(DbPublishPackages.Identity) », fait référence à la propriété de métadonnées Identity de la liste d’éléments DbPublishPackages . Cette notation, Outputs=%(ItemList.ItemMetadataName), est traduite comme suit :

  • Fractionnez les éléments dans DbPublishPackages en lots d’éléments qui contiennent la même valeur de métadonnées d’identité .
  • Exécutez la cible une fois par lot.

Notes

L’identité est l’une des valeurs de métadonnées intégrées qui est affectée à chaque élément lors de la création. Il fait référence à la valeur de l’attribut Include dans l’élément Item , c’est-à-dire le chemin d’accès et le nom de fichier de l’élément.

Dans ce cas, comme il ne doit jamais y avoir plusieurs éléments avec le même chemin et le même nom de fichier, nous travaillons essentiellement avec des tailles de lot d’un. La cible est exécutée une fois pour chaque package de base de données.

Vous pouvez voir une notation similaire dans la propriété _Cmd , qui génère une commande VSDBCMD avec les commutateurs appropriés.

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

Dans ce cas, %(DbPublishPackages.DatabaseConnectionString), %(DbPublishPackages.TargetDatabase) et %(DbPublishPackages.FullPath) font toutes référence aux valeurs de métadonnées de la collection d’éléments DbPublishPackages . La propriété _Cmd est utilisée par la tâche Exec , qui appelle la commande .

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

À la suite de cette notation, la tâche Exec crée des lots basés sur des combinaisons uniques des valeurs de métadonnées DatabaseConnectionString, TargetDatabase et FullPath , et la tâche s’exécute une fois pour chaque lot. Il s’agit d’un exemple de traitement par lots de tâches. Toutefois, étant donné que le traitement par lots au niveau de la cible a déjà divisé notre collection d’éléments en lots à élément unique, la tâche Exec s’exécute une fois et une seule fois pour chaque itération de la cible. En d’autres termes, cette tâche appelle l’utilitaire VSDBCMD une fois pour chaque package de base de données dans la solution.

Notes

Pour plus d’informations sur le traitement par lots de cibles et de tâches, consultez Traitement par lots MSBuild, Métadonnées d’élément dans le traitement par lot cible et Métadonnées d’élément dans le traitement par lots de tâches.

La cible PublishWebPackages

À ce stade, vous avez appelé la cible BuildProjects , qui génère un package de déploiement web pour chaque projet de l’exemple de solution. Chaque package est accompagné d’un fichier deploy.cmd , qui contient les commandes MSDeploy.exe requises pour déployer le package dans l’environnement cible, et d’un fichier SetParameters.xml , qui spécifie les détails nécessaires de l’environnement cible. Vous avez également appelé la cible GatherPackagesForPublishing , qui génère une collection d’éléments contenant les fichiers deploy.cmd qui vous intéressent. Essentiellement, la cible PublishWebPackages effectue les fonctions suivantes :

  • Il manipule le fichier SetParameters.xml pour chaque package afin d’inclure les détails corrects de l’environnement cible, à l’aide de la tâche XmlPoke .
  • Il appelle le fichier deploy.cmd pour chaque package, à l’aide des commutateurs appropriés.

Tout comme la cible PublishDbPackages , la cible PublishWebPackages utilise le traitement par lot cible pour s’assurer que la cible est exécutée une fois pour chaque package web.

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

Dans la cible, la tâche Exec est utilisée pour exécuter le fichier deploy.cmd pour chaque package web.

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

Pour plus d’informations sur la configuration du déploiement de packages web, consultez Génération et empaquetage de projets d’application web.

Conclusion

Cette rubrique a fourni une procédure pas à pas montrant comment fractionner les fichiers projet sont utilisés pour contrôler le processus de génération et de déploiement du début à la fin pour l’exemple de solution gestionnaire de contacts. Cette approche vous permet d’exécuter des déploiements complexes à l’échelle de l’entreprise en une seule étape reproductible, simplement en exécutant un fichier de commandes spécifique à l’environnement.

En savoir plus

Pour une présentation plus approfondie des fichiers projet et du WPP, consultez Inside the Microsoft Build Engine: Using MSBuild and Team Foundation Build par Sayed Ibrahim Hashimi et William Bartholomew, ISBN: 978-0-7356-4524-0.