Usar msbuild para ejecutar un perfil de publicación del sistema de archivos

86

Tengo un proyecto ac # .Net 4.0 creado con VS2010 y ahora se accede con VS2012.

Estoy tratando de publicar solo los archivos necesarios de este sitio web en una ubicación de destino (C: \ builds \ MyProject [Archivos])

Mi estructura de archivos: ./ProjectRoot/MyProject.csproj ./ProjectRoot/Properties/PublishProfiles/FileSystemDebug.pubxml

Estoy ejecutando lo siguiente a través de MSBuild:

C: \ Windows \ Microsoft.NET \ Framework \ v4.0.30319 \ MSBuild.exe ./ProjectRoot/MyProject.csproj / p: DeployOnBuild = true /p:PublishProfile=./ProjectRoot/Properties/PublishProfiles/FileSystemDebug.pubxml

Aquí está el xml en FileSystemDebug.pubxml

<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <WebPublishMethod>FileSystem</WebPublishMethod>
    <LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
    <LastUsedPlatform>Any CPU</LastUsedPlatform>
    <SiteUrlToLaunchAfterPublish />
    <ExcludeApp_Data>False</ExcludeApp_Data>
    <publishUrl>C:\builds\MyProject\</publishUrl>
    <DeleteExistingFiles>True</DeleteExistingFiles>
  </PropertyGroup>
</Project>

El comportamiento resultante es:

  • aquí se crea un archivo zip: ./ProjectRoot/obj/Debug/Package/MyProject.zip
  • No se implementa nada en <publishUrl>C:\builds\MyProject\</publishUrl>WTF
  • el archivo zip que se crea es un desayuno de cerdos y está lleno de archivos que no son necesarios para la aplicación.

Cuando ejecuto este perfil de publicación a través de Visual Studio, se crea una carpeta en * C: \ builds \ MyProject * y contiene los artefactos exactos que quiero.

¿Cómo obtengo este resultado simple de msbuild?

P. Roe
fuente

Respuestas:

51

FYI: Tuve el mismo problema con Visual Studio 2015. Después de muchas horas intentándolo, ahora puedo hacerlo msbuild myproject.csproj /p:DeployOnBuild=true /p:PublishProfile=myprofile.

Tuve que editar mi archivo .csproj para que funcionara. Contenía una línea como esta:

<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" 
  Condition="false" />

Cambié esta línea de la siguiente manera:

<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v14.0\WebApplications\Microsoft.WebApplication.targets" />

(Cambié 10.0 a 14.0, no estoy seguro de si esto era necesario. Pero definitivamente tuve que eliminar la parte de condición).

johanv
fuente
1
La importación condicional con Condition="false"existe para compatibilidad con versiones anteriores. VS2010 requiere que exista esta importación, incluso si se omite debido a la condición falsa. Si vuelve a mirar, verá que csproj contiene otra importación para la $(VSToolsPath)\WebApplications\Microsoft.WebApplication.targetsque se resuelve en el archivo de destinos para la versión actual de Visual Studio.
Steven Liekens
3
Tenga en cuenta el uso estratégico de $(MSBuildToolsVersion)la ruta de acceso a la cuenta para la versión adecuada VS: <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(MSBuildToolsVersion)\WebApplications\Microsoft.WebApplication.targets" Condition="false" />. Esto funcionó para mí en VS2015 Update 1.
Al Dass
42

Encontré la respuesta aquí: http://www.digitallycreated.net/Blog/59/locally-publishing-a-vs2010-asp.net-web-application-using-msbuild

Visual Studio 2010 tiene excelentes características de publicación de proyectos de aplicación web que le permiten publicar fácilmente su proyecto de aplicación web con solo hacer clic en un botón. Detrás de escena, la transformación de Web.config y la construcción del paquete se realiza mediante un script MSBuild masivo que se importa a su archivo de proyecto (que se encuentra en: C: \ Archivos de programa (x86) \ MSBuild \ Microsoft \ VisualStudio \ v10.0 \ Web \ Microsoft .Publicación.web.targets). Desafortunadamente, el script es enormemente complicado, desordenado e indocumentado (aparte de algunos comentarios a menudo mal escritos y en su mayoría inútiles en el archivo). Un gran diagrama de flujo de ese archivo y algo de documentación sobre cómo conectarlo sería bueno, pero lamentablemente parece faltar (o al menos no puedo encontrarlo).

Desafortunadamente, esto significa que realizar la publicación a través de la línea de comandos es mucho más opaco de lo que debería ser. Me sorprendió la falta de documentación en esta área, porque en estos días muchas tiendas usan un servidor de integración continua y algunas incluso hacen implementación automatizada (con lo que las funciones de publicación de VS2010 podrían ayudar mucho), así que habría pensado que habilitar esto ( ¡fácilmente!) habría sido un requisito bastante importante para la función.

De todos modos, después de buscar en el archivo Microsoft.Web.Publishing.targets durante horas y golpearme la cabeza contra la pared de prueba y error, me las arreglé para descubrir cómo Visual Studio parece realizar su magia con un clic en "Publicar en el sistema de archivos". y funciones de "Build Deployment Package". Me adentraré un poco en las secuencias de comandos de MSBuild, por lo que si no está familiarizado con MSBuild, le sugiero que consulte esta página de MSDN del curso intensivo.

Publicar en el sistema de archivos

El cuadro de diálogo Publicar en el sistema de archivos de VS2010 Me tomó un tiempo perder el tiempo porque esperaba que ocurriera un uso sensato de MSBuild. En cambio, VS2010 hace algo bastante extraño: pide a MSBuild que realice una especie de implementación parcial que prepara los archivos de la aplicación web en la carpeta obj de su proyecto, luego parece hacer una copia manual de esos archivos (es decir, fuera de MSBuild) en su carpeta de publicación de destino. Este es realmente un comportamiento de golpe porque MSBuild está diseñado para copiar archivos (y otras cosas relacionadas con la compilación), por lo que tendría sentido si todo el proceso fuera solo un objetivo de MSBuild al que llamó VS2010, no un objetivo y luego una copia manual.

Esto significa que hacer esto a través de MSBuild en la línea de comandos no es tan simple como invocar su archivo de proyecto con un objetivo en particular y establecer algunas propiedades. Deberá hacer lo que debería haber hecho VS2010: cree un objetivo usted mismo que realice la mitad de la implementación y luego copie los resultados en la carpeta de destino. Para editar el archivo de su proyecto, haga clic derecho en el proyecto en VS2010 y haga clic en Descargar proyecto, luego haga clic derecho nuevamente y haga clic en Editar. Desplácese hacia abajo hasta encontrar el elemento Importar que importa los destinos de la aplicación web (Microsoft.WebApplication.targets; este archivo importa el archivo Microsoft.Web.Publishing.targets mencionado anteriormente). Debajo de esta línea agregaremos nuestro nuevo objetivo, llamado PublishToFileSystem:

<Target Name="PublishToFileSystem"
        DependsOnTargets="PipelinePreDeployCopyAllFilesToOneFolder">
    <Error Condition="'$(PublishDestination)'==''"
           Text="The PublishDestination property must be set to the intended publishing destination." />
    <MakeDir Condition="!Exists($(PublishDestination))"
             Directories="$(PublishDestination)" />

    <ItemGroup>
        <PublishFiles Include="$(_PackageTempDir)\**\*.*" />
    </ItemGroup>

    <Copy SourceFiles="@(PublishFiles)"
          DestinationFiles="@(PublishFiles->'$(PublishDestination)\%(RecursiveDir)%(Filename)%(Extension)')"
          SkipUnchangedFiles="True" />
</Target>

Este destino depende del destino PipelinePreDeployCopyAllFilesToOneFolder, que es lo que VS2010 llama antes de realizar su copia manual. Un poco de investigación en Microsoft.Web.Publishing.targets muestra que llamar a este objetivo hace que los archivos del proyecto se coloquen en el directorio especificado por la propiedad _PackageTempDir.

La primera tarea que llamamos a nuestro objetivo es la tarea Error, sobre la cual hemos colocado una condición que asegura que la tarea solo ocurra si la propiedad PublishDestination no se ha establecido. Esto lo detectará y generará un error en la compilación en caso de que haya olvidado especificar la propiedad PublishDestination. Luego llamamos a la tarea MakeDir para crear ese directorio PublishDestination si aún no existe.

Luego definimos un elemento llamado PublishFiles que representa todos los archivos que se encuentran en la carpeta _PackageTempDir. Luego se llama a la tarea Copiar, que copia todos esos archivos en la carpeta Destino de publicación. El atributo DestinationFiles en el elemento Copy es un poco complejo; realiza una transformación de los elementos y convierte sus rutas en nuevas rutas arraigadas en la carpeta PublishDestination (consulte Metadatos de elementos conocidos para ver qué significan esos% () s).

Para llamar a este objetivo desde la línea de comandos, ahora podemos simplemente ejecutar este comando (obviamente cambiando el nombre del archivo del proyecto y las propiedades para que se adapte a usted):

msbuild Website.csproj "/p:Platform=AnyCPU;Configuration=Release;PublishDestination=F:\Temp\Publish" /t:PublishToFileSystem
P. Roe
fuente
3
No puedo entender el fragmento de código para el nuevo objetivo (muestra 01 02 03 ...). ¿Podrías editar?
fan711
2
Estoy de acuerdo con fan711. Sin embargo, la solución se describe en el enlace: ¿para qué fue entonces copiarla?
Антон Курьян
4
@ АнтонКурьян: Los enlaces tienden a desaparecer después de un tiempo, es por eso que las preguntas y respuestas en stackoverflow.com siempre deben ser independientes sin depender de recursos externos.
Oliver
Los resultados parecen que MSBuild no está utilizando el perfil de publicación en absoluto y, en cambio, está haciendo un paquete (¿quizás un paquete predeterminado?) Lo que hace la siguiente solución es replicar lo que está configurado para hacer el perfil, que Microsoft.Web.Publishing.targets maneja seleccionando el tipo correcto de su carpeta de implementación (para FileSystem). Entonces parece que estás reinventando la rueda aquí, en lugar de resolver ese problema. Pero no puedo decirlo con certeza sin su registro de MSBuild. Conseguí que el mío funcione, detalles en mi respuesta
GregS
1
La solución de GregS no me funciona. Se compila bien, pero no se copian archivos en el directorio de publicación
rushinge
19

Todavía tuve problemas después de probar todas las respuestas anteriores (uso Visual Studio 2013). No se copió nada en la carpeta de publicación.

El problema fue que si ejecuto MSBuild con un proyecto individual en lugar de una solución, tengo que poner un parámetro adicional que especifique la versión de Visual Studio:

/p:VisualStudioVersion=12.0

12.0es para VS2013, reemplácelo con la versión que use. Una vez que agregué este parámetro, simplemente funcionó.

La línea de comando completa se ve así:

MSBuild C:\PathToMyProject\MyProject.csproj /p:DeployOnBuild=true /p:PublishProfile=MyPublishProfile /p:VisualStudioVersion=12.0

Lo encontré aquí:

http://www.asp.net/mvc/overview/deployment/visual-studio-web-deployment/command-line-deployment

Ellos afirman:

Si especifica un proyecto individual en lugar de una solución, debe agregar un parámetro que especifique la versión de Visual Studio.

felix-b
fuente
12

Me parece que su perfil de publicación no se está utilizando y está haciendo algunos paquetes predeterminados. Los destinos de Microsoft Web Publish hacen todo lo que está haciendo anteriormente, selecciona los destinos correctos según la configuración.

Conseguí que el mío funcionara sin problemas desde el paso TeamCity MSBuild, pero especifiqué una ruta explícita al perfil, solo tienes que llamarlo por su nombre sin .pubxml (por ejemplo, FileSystemDebug). Se encontrará siempre que esté en la carpeta estándar, que es la suya.

Ejemplo:

C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe ./ProjectRoot/MyProject.csproj /p:DeployOnBuild=true /p:PublishProfile=FileSystemDebug

Tenga en cuenta que esto se hizo utilizando las versiones de Visual Studio 2012 de los destinos de publicación web de Microsoft, normalmente ubicados en "C: \ Archivos de programa (x86) \ MSBuild \ Microsoft \ VisualStudio \ v11.0 \ Web". Consulte la carpeta de implementación para conocer los tipos de implementación específicos que se utilizan.

GregS
fuente
MS ha realizado muchas mejoras desde que se publicó hace unos años, ¿gracias por la programación actualizada?
P. Roe
3

FYI: el mismo problema con la ejecución en un servidor de compilación (Jenkins con msbuild 15 instalado, impulsado desde VS 2017 en un proyecto web .NET Core 2.1).

En mi caso, fue el uso del destino "publicar" con msbuild lo que ignoró el perfil.

Entonces mi comando msbuild comenzó con:

msbuild /t:restore;build;publish

Esto desencadenó correctamente el proceso de publicación, pero ninguna combinación o variación de "/ p: PublishProfile = FolderProfile" funcionó para seleccionar el perfil que quería usar ("FolderProfile").

Cuando dejé de usar el destino de publicación:

msbuild /t:restore;build /p:DeployOnBuild=true /p:PublishProfile=FolderProfile

Pensé (tontamente) que no haría ninguna diferencia, pero tan pronto como usé el interruptor DeployOnBuild, recogió correctamente el perfil.

De Orbonia
fuente
3

En realidad, fusioné todas sus respuestas con mi propia solución sobre cómo resolver el problema anterior:

  1. Creo el archivo pubxml según mis necesidades
  2. Luego copio todos los parámetros del archivo pubxml a mi propia lista de parámetros "/ p: foo = bar" para msbuild.exe
  3. Tiro el archivo pubxml

El resultado es así:

msbuild /t:restore /t:build /p:WebPublishMethod=FileSystem /p:publishUrl=C:\builds\MyProject\ /p:DeleteExistingFiles=True /p:LastUsedPlatform="Any CPU" /p:Configuration=Release

Rainer
fuente
1

Primero verifique la versión de Visual Studio de la PC del desarrollador que puede publicar la solución (proyecto). como se muestra es para VS 2013

 /p:VisualStudioVersion=12.0

agregue la línea de comando anterior para especificar qué tipo de versión de Visual Studio debe construir el proyecto. Como respuestas anteriores, esto podría suceder cuando intentamos publicar solo un proyecto, no la solución completa.

Entonces el código completo sería algo como esto

"C: \ Windows \ Microsoft.NET \ Framework \ v4.0.30319 \ msbuild.exe" "C: \ Archivos de programa (x86) \ Jenkins \ workspace \ Jenkinssecondsample \ MVCSampleJenkins \ MVCSampleJenkins.csproj" / T: Build; Package / p : Configuración = DEBUG / p: OutputPath = "obj \ DEBUG" / p: DeployIisAppPath = "Sitio web predeterminado / jenkinsdemoapp" /p:VisualStudioVersion=12.0

Shammie
fuente
1
Lo siento shammakalubo, malinterpretaste mucho la pregunta.
P. Roe
1
@shammakalubo La respuesta es correcta, pero no se dice completamente. Este parámetro debe agregarse al comando mencionado por el OP, que luego se convertirá en: MSBuild C:\PathToMyProject\MyProject.csproj /p:DeployOnBuild=true /p:PublishProfile=MyPublishProfile /p:VisualStudioVersion=12.0Este parámetro es lo que me faltaba y solucionó mi problema. ¡Solo necesitas mencionar la respuesta completamente!
Syed Waqas
@WaqasShah Gracias, como mencionaste, edité mi respuesta y publiqué el código completo como se vería.
Shammie