Descripción del archivo de proyecto
por Jason Lee
Los archivos del proyecto de Microsoft Build Engine (MSBuild) se encuentran en el centro del proceso de compilación e implementación. Este tema comienza con una introducción conceptual de MSBuild y el archivo del proyecto. Describe los componentes clave que encontrará al trabajar con archivos del proyecto y funciona mediante un ejemplo de cómo puede usar archivos del proyecto para implementar aplicaciones reales.
Temas que se abordarán:
- Uso de archivos del proyecto de MSBuild para compilar proyectos en MSBuild.
- Integración de MSBuild con tecnologías de implementación, como la herramienta de implementación web (Web Deploy) de Internet Information Services (IIS).
- Procedimiento para comprender los componentes clave de un archivo del proyecto.
- Procedimiento para usar archivos del proyecto para compilar e implementar aplicaciones complejas.
MSBuild y el archivo del proyecto
Al crear y compilar soluciones en Visual Studio, Visual Studio usa MSBuild para compilar cada proyecto de la solución. Cada proyecto de Visual Studio incluye un archivo del proyecto MSBuild, con una extensión de archivo que refleja el tipo de proyecto, por ejemplo, un proyecto de C# (.csproj), un proyecto .NET de Visual Basic (.vbproj) o un proyecto de base de datos (.dbproj). Para compilar un proyecto, MSBuild debe procesar el archivo del proyecto asociado al proyecto. El archivo del proyecto es un documento XML que contiene toda la información y las instrucciones que MSBuild necesita para compilar el proyecto, incluidos el contenido, los requisitos de la plataforma, la información de versión, la configuración del servidor web o del servidor de bases de datos, y las tareas que se deben llevar a cabo.
Los archivos del proyecto de MSBuild se basan en el esquema XML de MSBuild y, como resultado, el proceso de compilación es totalmente abierto y transparente. Además, no es necesario instalar Visual Studio para usar el motor de MSBuild; el archivo ejecutable MSBuild.exe forma parte de .NET Framework y puede ejecutarlo desde un símbolo del sistema. Como desarrollador, puede crear archivos del proyecto de MSBuild propios, mediante el esquema XML de MSBuild, para imponer un control sofisticado y específico sobre cómo se compilan e implementan los proyectos. Estos archivos del proyecto personalizados funcionan exactamente de la misma manera que los que Visual Studio genera automáticamente.
Nota:
También puede usar archivos del proyecto de MSBuild con el servicio Team Build en Team Foundation Server (TFS). Por ejemplo, puede usar archivos del proyecto en escenarios de integración continua (CI) para automatizar la implementación en un entorno de prueba cuando se registra código nuevo. Para más información, vea Configuración de Team Foundation Server para la implementación web automatizada.
Convenciones de nomenclatura de archivos del proyecto
Al crear archivos del proyecto propios, puede usar cualquier extensión de archivo que quiera. Pero a fin de que las soluciones sean más fáciles de entender para otros usuarios, debe usar estas convenciones comunes:
- Use la extensión .proj al crear un archivo del proyecto que compile proyectos.
- Use la extensión .targets al crear un archivo del proyecto reutilizable para importarlo en otros archivos del proyecto. Los archivos con una extensión .targets normalmente no compilan nada por sí mismos, simplemente contienen instrucciones que se pueden importar en los archivos .proj.
Integración con tecnologías de implementación
Si ha trabajado con proyectos de aplicaciones web en Visual Studio 2010, como aplicaciones web ASP.NET y aplicaciones web ASP.NET MVC, sabrá que estos proyectos incluyen compatibilidad integrada para empaquetar e implementar la aplicación web en un entorno de destino. Las páginas Propiedades de estos proyectos incluyen las pestañas Empaquetar/publicar web y Empaquetar/publicar SQL que puede usar para configurar cómo se empaquetan e implementan los componentes de la aplicación. Aquí se muestra la pestaña Empaquetar/publicar web:
La tecnología subyacente a estas funcionalidades se conoce como Canalización de publicación web (WPP). WPP básicamente combina MSBuild y Web Deploy para proporcionar un proceso completo de compilación, empaquetado e implementación para las aplicaciones web.
La buena noticia es que puede aprovechar los puntos de integración que proporciona WPP al crear archivos del proyecto personalizados para proyectos web. Puede incluir instrucciones de implementación en el archivo del proyecto, lo que le permite compilar los proyectos, crear paquetes de implementación web e instalar estos paquetes en servidores remotos desde un único archivo del proyecto y una sola llamada a MSBuild. También puede llamar a cualquier otro ejecutable como parte del proceso de compilación. Por ejemplo, puede ejecutar la herramienta de línea de comandos VSDBCMD.exe para implementar una base de datos desde un archivo de esquema. A lo largo de este tema, verá cómo puede aprovechar estas funcionalidades para cumplir los requisitos de los escenarios de implementación empresarial.
Nota:
Para más información sobre cómo funciona el proceso de implementación de aplicaciones web, veaInformación general sobre la implementación de proyectos de aplicación web ASP.NET.
Anatomía de un archivo del proyecto
Antes de examinar el proceso de compilación con más detalle, merece la pena familiarizarse con la estructura básica de un archivo del proyecto de MSBuild. En esta sección se proporciona información general sobre los elementos más comunes que encontrará al revisar, editar o crear un archivo del proyecto. En concreto, obtendrá información sobre lo siguiente:
- Cómo usar propiedades para administrar variables para el proceso de compilación.
- Cómo usar elementos para identificar las entradas en el proceso de compilación, como archivos de código.
- Cómo usar destinos y tareas para proporcionar instrucciones de ejecución a MSBuild mediante propiedades y elementos definidos en otro lugar del archivo del proyecto.
Aquí se muestra la relación entre los elementos clave de un archivo del proyecto de MSBuild:
Elemento Project
El elemento raíz de todos los archivo del proyecto es Project. Además de identificar el esquema XML para el archivo del proyecto, el elemento Project puede incluir atributos a fin de especificar los puntos de entrada para el proceso de compilación. Por ejemplo, en la solución de ejemplo Contact Manager, el archivo Publish.proj especifica que la compilación debe comenzar con una llamada al destino denominado FullPublish.
<Project ToolsVersion="4.0" DefaultTargets="FullPublish"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
</Project>
Propiedades y condiciones
Normalmente, un archivo del proyecto debe proporcionar una gran cantidad de información diferente para compilar e implementar correctamente los proyectos. Estos fragmentos de información podrían incluir nombres de servidor, cadenas de conexión, credenciales, configuraciones de compilación, rutas de acceso de archivo de origen y de destino, y cualquier otra información que se quiera incluir para admitir la personalización. En un archivo del proyecto, las propiedades se deben definir dentro de un elemento PropertyGroup. Las propiedades de MSBuild constan de pares clave-valor. Dentro del elemento PropertyGroup, el nombre del elemento define la clave de propiedad y el contenido define el valor. Por ejemplo, podría definir propiedades denominadas ServerName y ConnectionString para almacenar un nombre de servidor estático y una cadena de conexión.
<PropertyGroup>
<ServerName>FABRIKAM\TEST1</ServerName>
<ConnectionString>
Data Source=FABRIKAM\TESTDB;InitialCatalog=ContactManager,...
</ConnectionString>
</PropertyGroup>
Para recuperar un valor de propiedad, use el formato $(NombreDeLaPropiedad). Por ejemplo, para recuperar el valor de la propiedad ServerName, tendría que escribir lo siguiente:
$(ServerName)
Nota:
Más adelante en este tema verá ejemplos de cómo y cuándo usar valores de propiedad.
La inserción de información como propiedades estáticas en un archivo del proyecto no siempre es el enfoque ideal para administrar el proceso de compilación. En muchos escenarios, querrá obtener la información de otros orígenes o permitir al usuario proporcionar la información desde el símbolo del sistema. MSBuild permite especificar cualquier valor de propiedad como parámetro de línea de comandos. Por ejemplo, el usuario podría proporcionar un valor para ServerName cuando ejecuta MSBuild.exe desde la línea de comandos.
msbuild.exe Publish.proj /p:ServerName=FABRIKAM\TESTWEB1
Nota:
Para más información sobre los argumentos y modificadores que puede usar con MSBuild.exe, vea Referencia de la línea de comandos de MSBuild.
Puede usar la misma sintaxis de propiedad para obtener los valores de las variables de entorno y las propiedades del proyecto integradas. Se definen muchas propiedades usadas habitualmente y puede utilizarlas en los archivos del proyecto mediante la inclusión del nombre de parámetro correspondiente. Por ejemplo, para recuperar la plataforma del proyecto actual (por ejemplo, x86 o AnyCpu) puede incluir la referencia de propiedad $(Plataforma) en el archivo del proyecto. Para más información, vea Macros para comandos y propiedades de compilación, Propiedades comunes de proyectos de MSBuild y Propiedades reservadas.
Las propiedades se suelen usar junto con condiciones. La mayoría de los elementos de MSBuild admiten el atributo Condition, que permite especificar los criterios con los que MSBuild debe evaluar el elemento. Por ejemplo, considere esta definición de propiedad:
<PropertyGroup>
<OutputRoot Condition=" '$(OutputRoot)'=='' ">..\Publish\Out\</OutputRoot>
...
</PropertyGroup>
Cuando MSBuild procesa esta definición de propiedad, primero comprueba si hay disponible un valor de propiedad $(OutputRoot). Si el valor de la propiedad está en blanco, es decir, el usuario no ha proporcionado un valor para esta propiedad, la condición se evalúa como true y el valor de la propiedad se establece en .. \Publish\Out. Si el usuario ha proporcionado un valor para esta propiedad, la condición se evalúa como false y no se usa el valor de la propiedad estática.
Para más información sobre las distintas formas en las que puede especificar condiciones, vea Condiciones de MSBuild.
Elementos y grupos de elementos
Uno de los roles importantes del archivo del proyecto es definir las entradas para el proceso de compilación. Normalmente, estas entradas son archivos: de código, de configuración, de comandos y cualquier otro archivo que necesite procesar o copiar como parte del proceso de compilación. En el esquema del proyecto de MSBuild, estas entradas se representan mediante elementos Item. En un archivo del proyecto, los elementos se deben definir dentro de un elemento ItemGroup. Como sucede con los elementos Property, puede asignar el nombre que quiera a un elemento Item. Pero debe especificar un atributo Include para identificar el archivo o el carácter comodín que representa el elemento.
<ItemGroup>
<ProjectsToBuild Include="$(SourceRoot)ContactManager-WCF.sln"/>
</ItemGroup>
Al especificar varios elementos Item con el mismo nombre, se crea eficazmente una lista con nombre de recursos. Una buena manera de ver esto en acción consiste en examinar el interior de uno de los archivos del proyecto que crea Visual Studio. Por ejemplo, el archivo ContactManager.Mvc.csproj de la solución de ejemplo incluye una gran cantidad de grupos de elementos, cada uno con varios elementos Item del mismo nombre.
<ItemGroup>
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Runtime.Serialization" />
<Reference Include="System.ServiceModel" />
...
</ItemGroup>
<ItemGroup>
<Compile Include="Controllers\AccountController.cs" />
<Compile Include="Controllers\ContactsController.cs" />
<Compile Include="Controllers\HomeController.cs" />
...
</ItemGroup>
<ItemGroup>
<Content Include="Content\Custom.css" />
<Content Include="CreateDatabase.sql" />
<Content Include="DropDatabase.sql" />
...
</ItemGroup>
De este modo, el archivo del proyecto indica a MSBuild que construya listas de archivos que se deben procesar de la misma manera: la lista Reference incluye ensamblados que deben estar presentes para una compilación correcta, la lista Compile incluye archivos de código que se deben compilar y la lista Content incluye recursos que se deben copiar sin modificar. Más adelante en este tema se verá cómo el proceso de compilación hace referencia a estos elementos y los usa.
Los elementos Item también pueden incluir elementos ItemMetadata secundarios. Se trata de pares clave-valor definidos por el usuario y, básicamente, representan propiedades específicas de ese elemento. Por ejemplo, muchos de los elementos Compile del archivo del proyecto incluyen elementos secundarios DependentUpon.
<Compile Include="Global.asax.cs">
<DependentUpon>Global.asax</DependentUpon>
</Compile>
Nota:
Además de los metadatos de elementos creados por el usuario, a todos los elementos se les asignan varios metadatos comunes al crearlos. Para obtener más información, consulte Metadatos de elementos conocidos.
Puede crear elementos ItemGroup dentro del elemento Project de nivel raíz o dentro de elementos Target específicos. Los elementos ItemGroup también admiten atributos Condition, lo que permite adaptar las entradas al proceso de compilación según condiciones como la configuración del proyecto o la plataforma.
Destinos y tareas
En el esquema de MSBuild, un elemento Task representa una instrucción de compilación individual (o tarea). MSBuild incluye una gran cantidad de tareas predefinidas. Por ejemplo:
- La tarea Copy copia archivos en una nueva ubicación.
- La tarea Csc invoca al compilador de Visual C#.
- La tarea Vbc invoca al compilador de Visual Basic.
- La tarea Exec ejecuta un programa especificado.
- La tarea Message escribe un mensaje en un registrador.
Nota:
Para obtener detalles completos de las tareas que están disponibles de forma predeterminada, vea Referencia de tareas de MSBuild. Para más información sobre las tareas, incluido cómo crear tareas personalizadas propias, vea Tareas de MSBuild.
Las tareas siempre deben estar incluidas en elementos Target. Un elemento Target es un conjunto de una o varias tareas que se ejecutan secuencialmente y un archivo del proyecto puede contener varios destinos. Cuando quiera ejecutar una tarea o un conjunto de tareas, invoque el destino en el que se incluyan. Por ejemplo,imagine que tiene un archivo del proyecto simple que registra un mensaje.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="LogMessage">
<Message Text="Hello world!" />
</Target>
</Project>
Puede invocar el destino desde la línea de comandos mediante el modificador /t para especificar el destino.
msbuild.exe Publish.proj /t:LogMessage
Como alternativa, puede agregar un atributo DefaultTargets al elemento Project para especificar los destinos que quiere invocar.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
DefaultTargets="FullPublish">
<Target Name="LogMessage">
<Message Text="Hello world!" />
</Target>
</Project>
En este caso, no es necesario especificar el destino desde la línea de comandos. Simplemente puede especificar el archivo del proyecto y MSBuild invocará el destino FullPublish automáticamente.
msbuild.exe Publish.proj
Tanto los destinos como las tareas pueden incluir atributos Condition. Por tanto, puede optar por omitir destinos completos o tareas individuales si se cumplen determinadas condiciones.
Por lo general, al crear tareas y destinos útiles, tendrá que hacer referencia a propiedades y elementos que ha definido en otro lugar del archivo de proyecto:
- Para usar un valor de propiedad, escriba $(NombreDeLaPropiedad), donde NombreDeLaPropiedad es el nombre del elemento Property o el nombre del parámetro.
- Para usar un elemento, escriba @(NombreDelElemento), donde NombreDelElemento es el nombre del elemento Item.
Nota:
Recuerde que si crea varios elementos con el mismo nombre, se crea una lista. Por el contrario, si crea varias propiedades con el mismo nombre, el último valor de propiedad que proporcione sobrescribirá las propiedades anteriores con el mismo nombre: una propiedad solo puede contener un único valor.
Por ejemplo, en el archivo Publish.proj de la solución de ejemplo, observe el destino BuildProjects.
<Target Name="BuildProjects" Condition=" '$(BuildingInTeamBuild)'!='true' ">
<MSBuild Projects="@(ProjectsToBuild)"
Properties="OutDir=$(OutputRoot);
Configuration=$(Configuration);
DeployOnBuild=true;
DeployTarget=Package"
Targets="Build" />
</Target>
En este ejemplo, puede observar estos puntos clave:
Si se especifica el parámetro BuildingInTeamBuild y tiene un valor true, no se ejecutará ninguna de las tareas de este destino.
El destino contiene una sola instancia de la tarea MSBuild. Esta tarea le permite compilar otros proyectos de MSBuild.
El elemento ProjectsToBuild se ha pasado a la tarea. Este elemento podría representar una lista de archivos del proyecto o solución, todos definidos por los elementos del elemento ProjectsToBuild dentro de un grupo de elementos. En este caso, el elemento ProjectsToBuild hace referencia a un único archivo de solución.
<ItemGroup> <ProjectsToBuild Include="$(SourceRoot)ContactManager-WCF.sln"/> </ItemGroup>
Los valores de propiedad pasados a la tarea MSBuild incluyen los parámetros OutputRoot y Configuration. Se establecen en valores de parámetro si se proporcionan, o bien en valores de propiedad estáticos en caso contrario.
<PropertyGroup> ... <Configuration Condition=" '$(Configuration)'=='' ">Release </Configuration> <OutputRoot Condition=" '$(OutputRoot)'=='' ">..\Publish\Out\ </OutputRoot> ... </PropertyGroup>
También puede ver que la tarea MSBuild invoca un destino denominado Build. Se trata de uno de los destinos integrados que se usan ampliamente en los archivos del proyecto de Visual Studio y están disponibles en los archivos del proyecto personalizados, como Build, Clean, Rebuild y Publish. Más adelante en este tema obtendrá más información sobre el uso de destinos y tareas para controlar el proceso de compilación y sobre la tarea MSBuild en particular.
Nota:
Para más información sobre de los destinos, vea Destinos de MSBuild.
División de archivos del proyecto para admitir varios entornos
Imagine que quiere poder implementar una solución en varios entornos, como servidores de prueba, plataformas de almacenamiento provisional y entornos de producción. La configuración puede variar considerablemente entre estos entornos, no solo en términos de nombres de servidor, cadenas de conexión, etc., sino también en términos de credenciales, configuración de seguridad y muchos otros factores. Si necesita hacerlo con regularidad, no es realmente conveniente editar varias propiedades en el archivo del proyecto cada vez que cambie el entorno de destino. Tampoco es una solución ideal exigir que se proporcione una lista infinita de valores de propiedad al proceso de compilación.
Afortunadamente hay una alternativa. MSBuild le permite dividir la configuración de compilación en varios archivos del proyecto. Para ver cómo funciona, en la solución de ejemplo, observe que hay dos archivos del proyecto personalizados:
- Publish.proj, que contiene propiedades, elementos y destinos comunes a todos los entornos.
- Env-Dev.proj, que contiene propiedades específicas de un entorno de desarrollador.
Ahora observe que el archivo Publish.proj incluye un elemento Import, inmediatamente debajo de la etiqueta Project de apertura.
<Import Project="$(TargetEnvPropsFile)"/>
El elemento Import se usa para importar el contenido de otro archivo del proyecto de MSBuild en el actual. En este caso, el parámetro TargetEnvPropsFile proporciona el nombre de archivo del archivo del proyecto que quiere importar. Puede proporcionar un valor para este parámetro al ejecutar MSBuild.
msbuild.exe Publish.proj /p:TargetEnvPropsFile=EnvConfig\Env-Dev.proj
Esto combina eficazmente el contenido de los dos archivos en un único archivo del proyecto. Con este enfoque, puede crear un archivo del proyecto que contenga la configuración de compilación universal y varios archivos del proyecto complementarios que contengan propiedades específicas del entorno. Como resultado, simplemente ejecutar un comando con un valor de parámetro diferente le permite implementar la solución en otro entorno.
Dividir los archivos del proyecto de esta manera es un procedimiento recomendado que puede seguir. Permite a los desarrolladores realizar la implementación en varios entornos mediante la ejecución de un único comando, a la vez que evita la duplicación de propiedades de compilación universales en varios archivos del proyecto.
Nota:
Para obtener instrucciones sobre cómo personalizar los archivos del proyecto específicos del entorno para entornos de servidor propios, vea Configuración de propiedades de implementación para un entorno de destino.
Conclusión
En este tema se ha proporcionado una introducción general a los archivos del proyecto de MSBuild y se ha explicado cómo puede crear archivos del proyecto personalizados propios para controlar el proceso de compilación. También se ha presentado el concepto de división de archivos del proyecto en instrucciones de compilación universales y propiedades de compilación específicas del entorno, para facilitar la compilación e implementación de proyectos en varios destinos.
En el tema siguiente, Descripción del proceso de compilación, se proporciona más información sobre cómo puede usar archivos del proyecto para controlar la compilación y la implementación mediante la implementación de una solución con un nivel realista de complejidad.
Lecturas adicionales
Para obtener una introducción más detallada a los archivos del proyecto y el WPP, vea Inside the Microsoft Build Engine: Using MSBuild and Team Foundation Build (Dentro de Microsoft Build Engine: uso de MSBuild y Team Foundation Build) Sayed Ibrahim Hashimiy William Bartholomew, ISBN: 978-0-7356-4524-0.