Informazioni sul processo di compilazione

di Jason Lee

In questo argomento viene fornita una procedura dettagliata di un processo di compilazione e distribuzione su scala aziendale. L'approccio descritto in questo argomento usa file di progetto di Microsoft Build Engine personalizzati (MSBuild) per fornire un controllo granulare su ogni aspetto del processo. All'interno dei file di progetto, le destinazioni MSBuild personalizzate vengono usate per eseguire utilità di distribuzione, ad esempio lo strumento di distribuzione Web IIS (Internet Information Services) (MSDeploy.exe) e l'utilità di distribuzione del database VSDBCMD.exe.

Nota

L'argomento precedente, Informazioni sul file di progetto, ha descritto i componenti chiave di un file di progetto MSBuild e ha introdotto il concetto di suddivisione dei file di progetto per supportare la distribuzione in più ambienti di destinazione. Se non si ha già familiarità con questi concetti, è necessario esaminare Informazioni sul file di progetto prima di eseguire questo argomento.

Questo argomento fa parte di una serie di esercitazioni basate sui requisiti di distribuzione aziendali di una società fittizia denominata Fabrikam, Inc. Questa serie di esercitazioni usa una soluzione di esempio, la soluzione Contact Manager, per rappresentare un'applicazione Web con un livello realistico di complessità, tra cui un'applicazione ASP.NET MVC 3, un servizio Windows Communication Foundation (WCF) e un progetto di database.

Il metodo di distribuzione al centro di queste esercitazioni si basa sull'approccio split project file descritto in Informazioni sul file di progetto, in cui il processo di compilazione è controllato da due file di progetto, uno contenente le istruzioni di compilazione applicabili a ogni ambiente di destinazione e uno contenente le impostazioni di compilazione e distribuzione specifiche dell'ambiente. In fase di compilazione, il file di progetto specifico dell'ambiente viene unito al file di progetto indipendente dall'ambiente per formare un set completo di istruzioni di compilazione.

Panoramica della compilazione e della distribuzione

Nella soluzione Contact Manager tre file controllano il processo di compilazione e distribuzione:

  • File di progetto universale (Publish.proj). Contiene istruzioni di compilazione e distribuzione che non cambiano tra gli ambienti di destinazione.
  • File di progetto specifico dell'ambiente (Env-Dev.proj). Contiene le impostazioni di compilazione e distribuzione specifiche di un determinato ambiente di destinazione. Ad esempio, è possibile usare il file Env-Dev.proj per fornire le impostazioni per uno sviluppatore o un ambiente di test e creare un file alternativo denominato Env-Stage.proj per fornire le impostazioni per un ambiente di gestione temporanea.
  • Un file di comando (Publish-Dev.cmd). Contiene un comando MSBuild.exe che specifica i file di progetto da eseguire. È possibile creare un file di comando per ogni ambiente di destinazione, in cui ogni file contiene un comando MSBuild.exe che specifica un file di progetto specifico dell'ambiente diverso. In questo modo lo sviluppatore viene distribuito in ambienti diversi semplicemente eseguendo il file di comando appropriato.

Nella soluzione di esempio è possibile trovare questi tre file nella cartella Pubblica soluzione.

Nella soluzione di esempio è possibile trovare tre file nella cartella Pubblica soluzione.

Prima di esaminare questi file in modo più dettagliato, si esaminerà il funzionamento del processo di compilazione complessivo quando si usa questo approccio. A livello generale, il processo di compilazione e distribuzione è simile al seguente:

Aspetto generale del processo di compilazione e distribuzione.

La prima cosa che accade è che i due file di progetto, uno contenente le istruzioni di compilazione e distribuzione universali, e uno contenente le impostazioni specifiche dell'ambiente, vengono uniti in un singolo file di progetto. MSBuild esegue quindi le istruzioni nel file di progetto. Compila ognuno dei progetti nella soluzione, usando il file di progetto per ogni progetto. Chiama quindi altri strumenti, ad esempio Distribuzione Web (MSDeploy.exe) e l'utilità VSDBCMD per distribuire il contenuto Web e i database nell'ambiente di destinazione.

Dall'inizio alla fine, il processo di compilazione e distribuzione esegue queste attività:

  1. Elimina il contenuto della directory di output, in preparazione di una nuova compilazione.

  2. Compila ogni progetto nella soluzione:

    1. Per i progetti Web, in questo caso, un'applicazione Web MVC ASP.NET e un servizio Web WCF, il processo di compilazione crea un pacchetto di distribuzione Web per ogni progetto.
    2. Per i progetti di database, il processo di compilazione crea un manifesto di distribuzione (file con estensione deploymanifest) per ogni progetto.
  3. Usa l'utilità VSDBCMD.exe per distribuire ogni progetto di database nella soluzione, usando varie proprietà dei file di progetto, una stringa di connessione di destinazione e un nome di database, insieme al file con estensione deploymanifest.

  4. Usa l'utilità MSDeploy.exe per distribuire ogni progetto Web nella soluzione, usando varie proprietà dei file di progetto per controllare il processo di distribuzione.

È possibile usare la soluzione di esempio per tracciare questo processo in modo più dettagliato.

Nota

Per indicazioni su come personalizzare i file di progetto specifici dell'ambiente per i propri ambienti server, vedere Configurare le proprietà di distribuzione per un ambiente di destinazione.

Richiamo del processo di compilazione e distribuzione

Per distribuire la soluzione Contact Manager in un ambiente di test per sviluppatori, lo sviluppatore esegue il file di comando Publish-Dev.cmd . Viene richiamato MSBuild.exe, specificando Publish.proj come file di progetto da eseguire e Env-Dev.proj come valore del parametro.

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

Nota

L'opzione /fl (breve per /fileLogger) registra l'output di compilazione in un file denominato msbuild.log nella directory corrente. Per altre informazioni, vedere le informazioni di riferimento sulla riga di comando di MSBuild.

A questo punto, MSBuild avvia l'esecuzione, carica il file Publish.proj e avvia l'elaborazione delle istruzioni al suo interno. La prima istruzione indica a MSBuild di importare il file di progetto specificato dal parametro TargetEnvPropsFile .

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

Il parametro TargetEnvPropsFile specifica il file Env-Dev.proj , quindi MSBuild unisce il contenuto del file Env-Dev.proj nel file Publish.proj .

Gli elementi successivi che MSBuild rileva nel file di progetto unito sono gruppi di proprietà. Le proprietà vengono elaborate nell'ordine in cui vengono visualizzate nel file. MSBuild crea una coppia chiave-valore per ogni proprietà, specificando che vengono soddisfatte le condizioni specificate. Le proprietà definite più avanti nel file sovrascriveranno tutte le proprietà con lo stesso nome definito in precedenza nel file. Si considerino ad esempio le proprietà OutputRoot .

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

Quando MSBuild elabora il primo elemento OutputRoot , fornendo un parametro denominato in modo analogo non è stato specificato, imposta il valore della proprietà OutputRoot su .. \Publish\Out. Quando rileva il secondo elemento OutputRoot , se la condizione restituisce true, sovrascriverà il valore della proprietà OutputRoot con il valore del parametro OutDir .

L'elemento successivo rilevato da MSBuild è un singolo gruppo di elementi contenente un elemento denominato ProjectsToBuild.

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

MSBuild elabora questa istruzione creando un elenco di elementi denominato ProjectsToBuild. In questo caso, l'elenco di elementi contiene un singolo valore, ovvero il percorso e il nome file del file della soluzione.

A questo punto, gli elementi rimanenti sono destinazioni. Le destinazioni vengono elaborate in modo diverso dalle proprietà e dagli elementi, essenzialmente le destinazioni non vengono elaborate a meno che non siano specificate in modo esplicito dall'utente o richiamate da un altro costrutto all'interno del file di progetto. Tenere presente che il tag Project di apertura include un attributo DefaultTargets .

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

Ciò indica a MSBuild di richiamare la destinazione FullPublish , se le destinazioni non vengono specificate quando viene richiamato MSBuild.exe. La destinazione FullPublish non contiene attività; specifica semplicemente un elenco di dipendenze.

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

Questa dipendenza indica a MSBuild che per eseguire la destinazione FullPublish , è necessario richiamare questo elenco di destinazioni nell'ordine specificato:

  1. Deve richiamare la destinazione Clean .
  2. Deve richiamare la destinazione BuildProjects .
  3. Deve richiamare la destinazione GatherPackagesForPublishing .
  4. Deve richiamare la destinazione PublishDbPackages .
  5. Deve richiamare la destinazione PublishWebPackages .

Destinazione pulita

La destinazione Clean elimina fondamentalmente la directory di output e tutto il relativo contenuto, come preparazione per una nuova compilazione.

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

Si noti che la destinazione include un elemento ItemGroup . Quando si definiscono proprietà o elementi all'interno di un elemento Target , si creano proprietà e elementi dinamici . In altre parole, le proprietà o gli elementi non vengono elaborati fino a quando non viene eseguita la destinazione. La directory di output potrebbe non esistere o contenere file fino all'inizio del processo di compilazione, quindi non è possibile compilare l'elenco _FilesToDelete come elemento statico; è necessario attendere fino a quando non è in corso l'esecuzione. Di conseguenza, si compila l'elenco come elemento dinamico all'interno della destinazione.

Nota

In questo caso, poiché la destinazione Clean è la prima da eseguire, non è necessario usare un gruppo di elementi dinamici. Tuttavia, è consigliabile usare proprietà dinamiche ed elementi in questo tipo di scenario, perché è consigliabile eseguire destinazioni in un ordine diverso a un certo punto.
È anche consigliabile evitare di dichiarare elementi che non verranno mai usati. Se sono presenti elementi che verranno usati solo da una destinazione specifica, è consigliabile inserirli all'interno della destinazione per rimuovere eventuali sovraccarichi non necessari nel processo di compilazione.

Gli elementi dinamici, la destinazione pulita è piuttosto semplice e usa le attività predefinite Message, Delete e RemoveDir per:

  1. Inviare un messaggio al logger.
  2. Compilare un elenco di file da eliminare.
  3. Eliminare i file.
  4. Rimuovere la directory di output.

Destinazione BuildProjects

BuildProjects ha come destinazione fondamentalmente la compilazione di tutti i progetti nella soluzione di esempio.

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

Questa destinazione è stata descritta in dettaglio nell'argomento precedente , Informazioni sul file di progetto, per illustrare il modo in cui le attività e le destinazioni fanno riferimento a proprietà ed elementi. A questo punto, si è interessati principalmente all'attività MSBuild . È possibile usare questa attività per compilare più progetti. L'attività non crea una nuova istanza di MSBuild.exe; usa l'istanza in esecuzione corrente per compilare ogni progetto. I punti chiave di interesse in questo esempio sono le proprietà di distribuzione:

  • La proprietà DeployOnBuild indica a MSBuild di eseguire tutte le istruzioni di distribuzione nelle impostazioni del progetto al termine della compilazione di ogni progetto.
  • La proprietà DeployTarget identifica la destinazione che si desidera richiamare dopo la compilazione del progetto. In questo caso, la destinazione pacchetto compila l'output del progetto in un pacchetto Web distribuibile.

Nota

La destinazione package richiama la pipeline di pubblicazione Web (WPP), che fornisce l'integrazione tra MSBuild e Distribuzione Web. Per esaminare le destinazioni predefinite fornite dal WPP, esaminare il file Microsoft.Web.Publishing.targets nella cartella %PROGRAMFILES(x86)%\MSBuild\Microsoft\VisualStudio\v10.0\Web.

Destinazione GatherPackagesForPublishing

Se si studia la destinazione GatherPackagesForPublishing , si noterà che non contiene effettivamente alcuna attività. Contiene invece un singolo gruppo di elementi che definisce tre elementi dinamici.

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

Questi elementi fanno riferimento ai pacchetti di distribuzione creati durante l'esecuzione della destinazione BuildProjects . Non è possibile definire questi elementi in modo statico nel file di progetto, perché i file a cui fanno riferimento gli elementi non esistono finché non viene eseguita la destinazione BuildProjects . Gli elementi devono invece essere definiti dinamicamente all'interno di una destinazione che non viene richiamata fino a quando non viene eseguita la destinazione BuildProjects .

Gli elementi non vengono usati all'interno di questa destinazione. Questa destinazione compila semplicemente gli elementi e i metadati associati a ogni valore di elemento. Una volta elaborati questi elementi, l'elemento PublishPackages conterrà due valori, ovvero il percorso del file ContactManager.Mvc.deploy.cmd e il percorso del file ContactManager.Service.deploy.cmd . Distribuzione Web crea questi file come parte del pacchetto Web per ogni progetto e questi sono i file che è necessario richiamare nel server di destinazione per distribuire i pacchetti. Se si apre uno di questi file, verrà visualizzato fondamentalmente un comando MSDeploy.exe con vari valori di parametro specifici della compilazione.

L'elemento DbPublishPackages conterrà un singolo valore, ovvero il percorso del file ContactManager.Database.deploymanifest .

Nota

Quando si compila un progetto di database viene generato un file con estensione deploymanifest e viene usato lo stesso schema di un file di progetto MSBuild. Contiene tutte le informazioni necessarie per distribuire un database, incluso il percorso dello schema del database (con estensione dbschema) e i dettagli degli script di pre-distribuzione e post-distribuzione. Per altre informazioni, vedere Panoramica della compilazione e della distribuzione del database.

Altre informazioni su come vengono creati i pacchetti di distribuzione e i manifesti di distribuzione del database e usati in Compilazione e creazione di pacchetti di progetti di applicazioni Web e distribuzione di progetti di database.

Destinazione PublishDbPackages

In breve, la destinazione PublishDbPackages richiama l'utilità VSDBCMD per distribuire il database ContactManager in un ambiente di destinazione. La configurazione della distribuzione del database comporta numerose decisioni e sfumature. Per altre informazioni, vedere Distribuzione di progetti di database e personalizzazione delle distribuzioni di database per più ambienti. In questo argomento ci concentreremo sul funzionamento effettivo di questa destinazione.

In primo luogo, si noti che il tag di apertura include un attributo Outputs .

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

Questo è un esempio di invio in batch di destinazione. Nei file di progetto MSBuild, l'invio in batch è una tecnica per l'iterazione delle raccolte. Il valore dell'attributo Outputs , "%(DbPublishPackages.Identity)" fa riferimento alla proprietà Deimetadati Identity dell'elenco di elementi DbPublishPackages. Questa notazione , Outputs=%(ItemList.ItemMetadataName), viene convertita come:

  • Suddividere gli elementi in DbPublishPackage in batch di elementi che contengono lo stesso valore dei metadati Identity .
  • Eseguire la destinazione una volta per batch.

Nota

Identity è uno dei valori di metadati predefiniti assegnati a ogni elemento alla creazione. Fa riferimento al valore dell'attributo Include nell'elemento Item , ovvero il percorso e il nome file dell'elemento.

In questo caso, poiché non dovrebbero mai essere presenti più di un elemento con lo stesso percorso e lo stesso nome file, si sta essenzialmente lavorando con dimensioni batch di uno. La destinazione viene eseguita una volta per ogni pacchetto di database.

È possibile visualizzare una notazione simile nella proprietà _Cmd , che compila un comando VSDBCMD con le opzioni appropriate.

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

In questo caso, %(DbPublishPackages.DatabaseConnectionString), %(DbPublishPackages.TargetDatabase)e %(DbPublishPackages.FullPath) fanno riferimento ai valori dei metadati dell'insieme di elementi DbPublishPackages . La proprietà _Cmd viene utilizzata dall'attività Exec, che richiama il comando .

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

In seguito a questa notazione, l'attività Exec creerà batch basati su combinazioni univoche dei valori di metadati DatabaseConnectionString, TargetDatabase e FullPath e l'attività verrà eseguita una volta per ogni batch. Questo è un esempio di invio in batch di attività. Tuttavia, poiché il batch a livello di destinazione ha già diviso la raccolta di elementi in batch a singolo elemento, l'attività Exec verrà eseguita una sola volta e una sola volta per ogni iterazione della destinazione. In altre parole, questa attività richiama l'utilità VSDBCMD una volta per ogni pacchetto di database nella soluzione.

Nota

Per altre informazioni sull'invio in batch di destinazione e attività, vedere Batching msBuild, metadati degli elementi in batch di destinazione e metadati degli elementi in Batch attività.

Destinazione PublishWebPackages

A questo punto, è stata richiamata la destinazione BuildProjects , che genera un pacchetto di distribuzione Web per ogni progetto nella soluzione di esempio. L'accompagnamento di ogni pacchetto è un file deploy.cmd che contiene i comandi MSDeploy.exe necessari per distribuire il pacchetto nell'ambiente di destinazione e un file diSetParameters.xml , che specifica i dettagli necessari dell'ambiente di destinazione. È stata richiamata anche la destinazione GatherPackagesForPublishing , che genera una raccolta di elementi contenente i file deploy.cmd a cui si è interessati. Essenzialmente, la destinazione PublishWebPackages esegue queste funzioni:

  • Modifica il file diSetParameters.xml per ogni pacchetto per includere i dettagli corretti per l'ambiente di destinazione, usando l'attività XmlPoke .
  • Richiama il file deploy.cmd per ogni pacchetto, usando le opzioni appropriate.

Analogamente alla destinazione PublishDbPackages , la destinazione PublishWebPackages usa l'invio in batch di destinazione per garantire che la destinazione venga eseguita una sola volta per ogni pacchetto Web.

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

All'interno della destinazione, l'attività Exec viene usata per eseguire il file deploy.cmd per ogni pacchetto Web.

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

Per altre informazioni sulla configurazione della distribuzione di pacchetti Web, vedere Compilazione e creazione di pacchetti di progetti di applicazioni Web.

Conclusione

In questo argomento è stata fornita una procedura dettagliata sull'uso dei file di progetto divisi per controllare il processo di compilazione e distribuzione dall'inizio alla fine per la soluzione di esempio Contact Manager. L'uso di questo approccio consente di eseguire distribuzioni complesse su scala aziendale in un singolo passaggio ripetibile, semplicemente eseguendo un file di comando specifico dell'ambiente.

Altre informazioni

Per un'introduzione più approfondita ai file di progetto e al WPP, vedere Inside the Microsoft Build Engine: Using MSBuild and Team Foundation Build by Sayed Ibrahim Hashimi and William Bartholomew, ISBN: 978-0-7356-4524-0.