Utilisation de msbuild pour exécuter un profil de publication de système de fichiers

86

J'ai un projet ac # .Net 4.0 créé avec VS2010 et maintenant accessible avec VS2012.

J'essaie de publier uniquement les fichiers nécessaires de ce site Web vers un emplacement de destination (C: \ builds \ MyProject [Files])

Ma structure de fichiers: ./ProjectRoot/MyProject.csproj ./ProjectRoot/Properties/PublishProfiles/FileSystemDebug.pubxml

J'exécute ce qui suit via MSBuild:

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

Voici le xml dans 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>

Le comportement résultant est:

  • un fichier zip est créé ici: ./ProjectRoot/obj/Debug/Package/MyProject.zip
  • Rien n'est déployé sur <publishUrl>C:\builds\MyProject\</publishUrl>WTF
  • le fichier zip qui est créé est un petit-déjeuner de porcs et plein de fichiers qui ne sont pas nécessaires pour l'application.

Lorsque j'exécute ce profil de publication via Visual Studio, un dossier est créé dans * C: \ builds \ MyProject * et contient les artefacts exacts que je veux.

Comment obtenir ce résultat simple de msbuild?

P. Roe
la source

Réponses:

51

FYI: J'ai eu le même problème avec Visual Studio 2015. Après de nombreuses heures à essayer, je peux maintenant le faire msbuild myproject.csproj /p:DeployOnBuild=true /p:PublishProfile=myprofile.

J'ai dû modifier mon fichier .csproj pour le faire fonctionner. Il contenait une ligne comme celle-ci:

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

J'ai changé cette ligne comme suit:

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

(J'ai changé 10.0 en 14.0, je ne sais pas si c'était nécessaire. Mais j'ai définitivement dû supprimer la partie condition.)

Johanv
la source
1
L'importation conditionnelle avec Condition="false"existe pour la compatibilité descendante. VS2010 nécessite que cette importation existe, même si elle est ignorée en raison de la condition erronée. Si vous regardez à nouveau, vous verrez que le csproj contient une autre importation pour $(VSToolsPath)\WebApplications\Microsoft.WebApplication.targetslaquelle résout le fichier cibles pour la version actuelle de Visual Studio.
Steven Liekens
3
Notez l'utilisation stratégique de $(MSBuildToolsVersion)la voie pour tenir compte de la bonne Version VS: <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(MSBuildToolsVersion)\WebApplications\Microsoft.WebApplication.targets" Condition="false" />. Cela a fonctionné pour moi sur VS2015 Update 1.
Al Dass
42

J'ai trouvé la réponse ici: http://www.digitallycreated.net/Blog/59/locally-publishing-a-vs2010-asp.net-web-application-using-msbuild

Visual Studio 2010 propose de nouvelles fonctionnalités de publication de projet d'application Web qui vous permettent de publier facilement votre projet d'application Web en un clic. Dans les coulisses, la transformation Web.config et la construction du package sont effectuées par un script MSBuild massif qui est importé dans votre fichier de projet (trouvé à: C: \ Program Files (x86) \ MSBuild \ Microsoft \ VisualStudio \ v10.0 \ Web \ Microsoft .Web.Publishing.targets). Malheureusement, le script est extrêmement compliqué, désordonné et non documenté (à part certains commentaires souvent mal orthographiés et pour la plupart inutiles dans le fichier). Un gros organigramme de ce fichier et de la documentation sur la façon de s'y connecter serait bien, mais il semble malheureusement manquer (ou du moins je ne le trouve pas).

Malheureusement, cela signifie que la publication via la ligne de commande est beaucoup plus opaque que nécessaire. J'ai été surpris par le manque de documentation dans ce domaine, car de nos jours, de nombreux magasins utilisent un serveur d'intégration continue et certains font même un déploiement automatisé (avec lequel les fonctionnalités de publication VS2010 pourraient beaucoup aider), alors j'aurais pensé que l'activation de cela ( facilement!) aurait été une exigence assez principale pour la fonctionnalité.

Quoi qu'il en soit, après avoir fouillé le fichier Microsoft.Web.Publishing.targets pendant des heures et m'être cogné la tête contre le mur d'essais et d'erreurs, j'ai réussi à comprendre comment Visual Studio semble exécuter sa magie en un clic "Publier dans le système de fichiers" et les fonctionnalités «Build Deployment Package». Je vais entrer dans un peu de script MSBuild, donc si vous n'êtes pas familier avec MSBuild, je vous suggère de consulter cette page MSDN du cours intensif.

Publier dans le système de fichiers

La boîte de dialogue Publier dans le système de fichiers de VS2010 La publication dans le système de fichiers m'a pris un certain temps, car je m'attendais à ce qu'une utilisation raisonnable de MSBuild se produise. Au lieu de cela, VS2010 fait quelque chose d'assez étrange: il appelle MSBuild pour effectuer une sorte de semi-déploiement qui prépare les fichiers de l'application Web dans le dossier obj de votre projet, puis il semble faire une copie manuelle de ces fichiers (c'est-à-dire en dehors de MSBuild) dans votre dossier de publication cible. C'est vraiment un comportement de folie car MSBuild est conçu pour copier des fichiers (et d'autres éléments liés à la construction), il serait donc logique que l'ensemble du processus ne soit qu'une seule cible MSBuild appelée par VS2010, pas une cible, puis une copie manuelle.

Cela signifie que faire cela via MSBuild sur la ligne de commande n'est pas aussi simple que d'appeler votre fichier de projet avec une cible particulière et de définir certaines propriétés. Vous devrez faire ce que VS2010 aurait dû faire: créez vous-même une cible qui effectue le demi-déploiement, puis copie les résultats dans le dossier cible. Pour modifier votre fichier de projet, faites un clic droit sur le projet dans VS2010 et cliquez sur Décharger le projet, puis cliquez à nouveau avec le bouton droit et cliquez sur Modifier. Faites défiler vers le bas jusqu'à ce que vous trouviez l'élément Import qui importe les cibles d'application Web (Microsoft.WebApplication.targets; ce fichier lui-même importe le fichier Microsoft.Web.Publishing.targets mentionné précédemment). Sous cette ligne, nous ajouterons notre nouvelle cible, appelée 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>

Cette cible dépend de la cible PipelinePreDeployCopyAllFilesToOneFolder, qui est ce que VS2010 appelle avant d'effectuer sa copie manuelle. Certains fouilles dans Microsoft.Web.Publishing.targets montrent que l'appel de cette cible entraîne le placement des fichiers de projet dans le répertoire spécifié par la propriété _PackageTempDir.

La première tâche que nous appelons dans notre cible est la tâche Error, sur laquelle nous avons placé une condition qui garantit que la tâche ne se produit que si la propriété PublishDestination n'a pas été définie. Cela vous interceptera et sortira une erreur de la construction au cas où vous auriez oublié de spécifier la propriété PublishDestination. Nous appelons ensuite la tâche MakeDir pour créer ce répertoire PublishDestination s'il n'existe pas déjà.

Nous définissons ensuite un élément appelé PublishFiles qui représente tous les fichiers trouvés sous le dossier _PackageTempDir. La tâche de copie est alors appelée et copie tous ces fichiers dans le dossier de destination de publication. L'attribut DestinationFiles sur l'élément Copy est un peu complexe; il effectue une transformation des éléments et convertit leurs chemins en nouveaux chemins enracinés dans le dossier PublishDestination (consultez Métadonnées d'élément bien connues pour voir ce que signifient ces% () s).

Pour appeler cette cible à partir de la ligne de commande, nous pouvons maintenant simplement exécuter cette commande (en changeant évidemment le nom du fichier du projet et les propriétés selon vos besoins):

msbuild Website.csproj "/p:Platform=AnyCPU;Configuration=Release;PublishDestination=F:\Temp\Publish" /t:PublishToFileSystem
P. Roe
la source
3
Je n'arrive pas à comprendre l'extrait de code de la nouvelle cible (il montre 01 02 03 ...). Pourriez-vous s'il vous plaît modifier?
fan711
2
Je suis d'accord avec fan711. Cependant, la solution est décrite sur le lien - pourquoi était-ce alors de la copier?
Антон Курьян
4
@ АнтонКурьян: Les liens ont tendance à mourir après un certain temps, c'est pourquoi les questions et réponses sur stackoverflow.com doivent toujours être autonomes sans dépendre de ressources externes.
Oliver le
Les résultats semblent indiquer que le profil de publication n'est pas du tout utilisé par MSBuild, et qu'il crée plutôt un package (peut-être une valeur par défaut?). Ce que votre solution ci-dessous fait pour répliquer ce que le profil est configuré pour faire, que Microsoft.Web.Publishing.targets gère en sélectionnant le type correct dans son dossier de déploiement (pour FileSystem). On dirait donc que vous réinventez la roue ici, au lieu de résoudre ce problème. Mais je ne peux pas le dire avec certitude sans votre journal MSBuild. J'ai le mien au travail, les détails dans ma réponse
GregS
1
La solution de GregS ne fonctionne pas pour moi. Construit bien, mais aucun fichier n'est copié dans le répertoire de publication
rushinge
19

J'ai encore des problèmes après avoir essayé toutes les réponses ci-dessus (j'utilise Visual Studio 2013). Rien n'a été copié dans le dossier de publication.

Le hic, c'est que si j'exécute MSBuild avec un projet individuel au lieu d'une solution, je dois mettre un paramètre supplémentaire qui spécifie la version de Visual Studio:

/p:VisualStudioVersion=12.0

12.0est pour VS2013, remplacez-le par la version que vous utilisez. Une fois que j'ai ajouté ce paramètre, cela a juste fonctionné.

La ligne de commande complète ressemble à ceci:

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

Je l'ai trouvé ici:

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

Ils déclarent:

Si vous spécifiez un projet individuel au lieu d'une solution, vous devez ajouter un paramètre qui spécifie la version de Visual Studio.

félix-b
la source
12

Il me semble que votre profil de publication n'est pas utilisé et fait un empaquetage par défaut. Les cibles Microsoft Web Publish font tout ce que vous faites ci-dessus, elles sélectionnent les cibles correctes en fonction de la configuration.

J'ai fait fonctionner le mien sans problème depuis l'étape TeamCity MSBuild, mais j'ai spécifié un chemin explicite vers le profil, il vous suffit de l'appeler par son nom sans .pubxml (par exemple FileSystemDebug). Il sera trouvé aussi longtemps que dans le dossier standard, qui est le vôtre.

Exemple:

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

Notez que cela a été fait à l'aide des versions Visual Studio 2012 des cibles Microsoft Web Publish, normalement situées dans «C: \ Program Files (x86) \ MSBuild \ Microsoft \ VisualStudio \ v11.0 \ Web». Consultez le dossier de déploiement pour les cibles de types de déploiement spécifiques qui sont utilisées

GregS
la source
MS a fait beaucoup d'améliorations depuis sa publication il y a quelques années, merci pour la programmation mise à jour?
P. Roe
3

Pour info: même problème avec l'exécution sur un serveur de build (Jenkins avec msbuild 15 installé, piloté depuis VS 2017 sur un projet web .NET Core 2.1).

Dans mon cas, c'était l'utilisation de la cible «publier» avec msbuild qui ignorait le profil.

Donc, ma commande msbuild a commencé par:

msbuild /t:restore;build;publish

Cela a correctement déclenché le processus de publication, mais aucune combinaison ou variation de "/ p: PublishProfile = FolderProfile" n'a jamais fonctionné pour sélectionner le profil que je voulais utiliser ("FolderProfile").

Lorsque j'ai arrêté d'utiliser la cible de publication:

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

J'ai (bêtement) pensé que cela ne ferait aucune différence, mais dès que j'ai utilisé le commutateur DeployOnBuild, il a correctement pris le profil.

Depuis Orbonia
la source
3

En fait, j'ai fusionné toutes vos réponses à ma propre solution pour résoudre le problème ci-dessus:

  1. Je crée le fichier pubxml selon mes besoins
  2. Ensuite, je copie tous les paramètres du fichier pubxml dans ma propre liste de paramètres "/ p: foo = bar" pour msbuild.exe
  3. Je jette le fichier pubxml

Le résultat est comme ça:

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

Rainer
la source
1

Vérifiez d'abord la version Visual studio du PC développeur qui peut publier la solution (projet). comme indiqué est pour VS 2013

 /p:VisualStudioVersion=12.0

ajoutez la ligne de commande ci-dessus pour spécifier le type de version de Visual Studio qui doit générer le projet. Comme les réponses précédentes, cela peut se produire lorsque nous essayons de publier un seul projet, pas la solution entière.

Donc, le code complet serait quelque chose comme ça

"C: \ Windows \ Microsoft.NET \ Framework \ v4.0.30319 \ msbuild.exe" "C: \ Program Files (x86) \ Jenkins \ workspace \ Jenkinssecondsample \ MVCSampleJenkins \ MVCSampleJenkins.csproj" / T: Build; Package / p : Configuration = DEBUG / p: OutputPath = "obj \ DEBUG" / p: DeployIisAppPath = "Site Web par défaut / jenkinsdemoapp" /p:VisualStudioVersion=12.0

Shammie
la source
1
Désolé shammakalubo vous avez beaucoup mal interprété la question.
P. Roe
1
@shammakalubo La réponse est juste, mais ce n'est pas tout à fait indiqué. Ce paramètre doit être ajouté à la commande mentionnée par l'OP, qui deviendra alors: MSBuild C:\PathToMyProject\MyProject.csproj /p:DeployOnBuild=true /p:PublishProfile=MyPublishProfile /p:VisualStudioVersion=12.0Ce paramètre est ce qui me manquait et a résolu mon problème. Il vous suffit de mentionner complètement la réponse!
Syed Waqas
@WaqasShah Merci, Comme vous l'avez mentionné, j'ai édité ma réponse et publié le code complet à quoi cela ressemblerait.
Shammie