Verwenden von msbuild zum Ausführen eines Dateisystem-Veröffentlichungsprofils

86

Ich habe ein mit VS2010 erstelltes ac # .Net 4.0-Projekt, auf das jetzt mit VS2012 zugegriffen wird.

Ich versuche, nur die benötigten Dateien von dieser Website an einem Zielspeicherort zu veröffentlichen (C: \ Builds \ MyProject [Dateien]).

Meine Dateistruktur: ./ProjectRoot/MyProject.csproj ./ProjectRoot/Properties/PublishProfiles/FileSystemDebug.pubxml

Ich führe folgendes über MSBuild aus:

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

Hier ist die XML in 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>

Das resultierende Verhalten ist:

  • Hier wird eine Zip-Datei erstellt: ./ProjectRoot/obj/Debug/Package/MyProject.zip
  • <publishUrl>C:\builds\MyProject\</publishUrl>WTF wird nichts bereitgestellt
  • Die erstellte Zip-Datei ist ein Schweinefrühstück und voller Dateien, die für die Anwendung nicht benötigt werden.

Wenn ich dieses Veröffentlichungsprofil über Visual Studio ausführe, wird ein Ordner unter * C: \ Builds \ MyProject * erstellt. der genau die gewünschten Artefakte enthält.

Wie bekomme ich dieses einfache Ergebnis von msbuild?

P. Roe
quelle

Antworten:

51

Zu Ihrer Information: Ich hatte das gleiche Problem mit Visual Studio 2015. Nach vielen Stunden des Versuchs kann ich es jetzt tun msbuild myproject.csproj /p:DeployOnBuild=true /p:PublishProfile=myprofile .

Ich musste meine .csproj-Datei bearbeiten, damit sie funktioniert. Es enthielt eine Zeile wie diese:

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

Ich habe diese Zeile wie folgt geändert:

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

(Ich habe 10.0 auf 14.0 geändert und bin mir nicht sicher, ob dies notwendig ist. Aber ich musste den Bedingungsteil definitiv entfernen.)

johanv
quelle
1
Der bedingte Import mit Condition="false"ist aus Gründen der Abwärtskompatibilität vorhanden. Für VS2010 muss dieser Import vorhanden sein, auch wenn er aufgrund der falschen Bedingung übersprungen wird. Wenn Sie noch einmal nachsehen, werden Sie feststellen, dass das csproj einen weiteren Import enthält, $(VSToolsPath)\WebApplications\Microsoft.WebApplication.targetsder in die Zieldatei für die aktuelle Version von Visual Studio aufgelöst wird.
Steven Liekens
3
Beachten Sie die strategische Verwendung von $(MSBuildToolsVersion)im Pfad, um die richtige VS-Version zu berücksichtigen : <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(MSBuildToolsVersion)\WebApplications\Microsoft.WebApplication.targets" Condition="false" />. Dies funktionierte für mich bei VS2015 Update 1.
Al Dass
42

Die Antwort finden Sie hier: http://www.digitallycreated.net/Blog/59/locally-publishing-a-vs2010-asp.net-web-application-using-msbuild

Visual Studio 2010 verfügt über großartige neue Veröffentlichungsfunktionen für Webanwendungsprojekte, mit denen Sie Ihr Webanwendungsprojekt auf Knopfdruck einfach veröffentlichen können. Hinter den Kulissen wird die Web.config-Transformation und die Paketerstellung von einem massiven MSBuild-Skript durchgeführt, das in Ihre Projektdatei importiert wird (zu finden unter: C: \ Programme (x86) \ MSBuild \ Microsoft \ VisualStudio \ v10.0 \ Web \ Microsoft .Web.Publishing.targets). Leider ist das Skript sehr kompliziert, chaotisch und undokumentiert (abgesehen von einigen oft schlecht geschriebenen und meist nutzlosen Kommentaren in der Datei). Ein großes Flussdiagramm dieser Datei und einige Dokumentationen zum Einbinden wären nett, scheinen aber leider zu fehlen (oder zumindest kann ich sie nicht finden).

Leider bedeutet dies, dass das Veröffentlichen über die Befehlszeile viel undurchsichtiger ist, als es sein muss. Ich war überrascht über den Mangel an Dokumentation in diesem Bereich, da heutzutage viele Geschäfte einen kontinuierlichen Integrationsserver verwenden und einige sogar eine automatisierte Bereitstellung durchführen (bei der die VS2010-Veröffentlichungsfunktionen sehr hilfreich sein könnten). Ich hätte also gedacht, dass dies möglich ist ( leicht!) wäre eine ziemlich wichtige Voraussetzung für die Funktion gewesen.

Nachdem ich mich stundenlang in der Microsoft.Web.Publishing.targets-Datei umgesehen und meinen Kopf gegen die Trial-and-Error-Wand geschlagen habe, habe ich es geschafft, herauszufinden, wie Visual Studio seine magische Wirkung mit einem Klick auf "In Dateisystem veröffentlichen" zu entfalten scheint. und Funktionen zum Erstellen eines Bereitstellungspakets. Ich werde mich mit MSBuild-Skripten befassen. Wenn Sie also nicht mit MSBuild vertraut sind, empfehlen wir Ihnen, diese MSDN-Seite des Crashkurses zu lesen.

Im Dateisystem veröffentlichen

Es dauerte eine Weile, bis ich das Dialogfeld "In Dateisystem veröffentlichen" für VS2010 veröffentlicht hatte, da ich erwartet hatte, dass MSBuild sinnvoll eingesetzt wird. Stattdessen macht VS2010 etwas ziemlich Seltsames: Es fordert MSBuild auf, eine Art Halbbereitstellung durchzuführen, die die Dateien der Webanwendung im obj-Ordner Ihres Projekts vorbereitet, und dann scheint es eine manuelle Kopie dieser Dateien zu erstellen (dh außerhalb von MSBuild). in Ihren Zielveröffentlichungsordner. Dies ist ein wirklich verrücktes Verhalten, da MSBuild zum Kopieren von Dateien (und anderen Build-bezogenen Dingen) entwickelt wurde. Es wäre also sinnvoll, wenn der gesamte Prozess nur ein von VS2010 aufgerufenes MSBuild-Ziel wäre, kein Ziel, sondern eine manuelle Kopie.

Dies bedeutet, dass dies über MSBuild in der Befehlszeile nicht so einfach ist wie das Aufrufen Ihrer Projektdatei mit einem bestimmten Ziel und das Festlegen einiger Eigenschaften. Sie müssen das tun, was VS2010 hätte tun sollen: Erstellen Sie selbst ein Ziel, das die Halbbereitstellung durchführt, und kopieren Sie die Ergebnisse in den Zielordner. Um Ihre Projektdatei zu bearbeiten, klicken Sie mit der rechten Maustaste auf das Projekt in VS2010 und klicken Sie auf Projekt entladen. Klicken Sie dann erneut mit der rechten Maustaste und klicken Sie auf Bearbeiten. Scrollen Sie nach unten, bis Sie das Import-Element finden, das die Webanwendungsziele importiert (Microsoft.WebApplication.targets; diese Datei selbst importiert die zuvor erwähnte Microsoft.Web.Publishing.targets-Datei). Unter dieser Zeile fügen wir unser neues Ziel namens PublishToFileSystem hinzu:

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

Dieses Ziel hängt vom PipelinePreDeployCopyAllFilesToOneFolder-Ziel ab, das VS2010 aufruft, bevor es manuell kopiert wird. Einige Untersuchungen in Microsoft.Web.Publishing.targets zeigen, dass beim Aufrufen dieses Ziels die Projektdateien in dem durch die Eigenschaft _PackageTempDir angegebenen Verzeichnis abgelegt werden.

Die erste Aufgabe, die wir in unserem Ziel aufrufen, ist die Fehleraufgabe, für die wir eine Bedingung festgelegt haben, die sicherstellt, dass die Aufgabe nur ausgeführt wird, wenn die PublishDestination-Eigenschaft nicht festgelegt wurde. Dadurch werden Sie abgefangen und der Build wird fehlerhaft, falls Sie vergessen haben, die PublishDestination-Eigenschaft anzugeben. Wir rufen dann die MakeDir-Task auf, um dieses PublishDestination-Verzeichnis zu erstellen, falls es noch nicht vorhanden ist.

Anschließend definieren wir ein Element namens PublishFiles, das alle im Ordner _PackageTempDir gefundenen Dateien darstellt. Anschließend wird die Aufgabe "Kopieren" aufgerufen, mit der alle diese Dateien in den Ordner "Ziel veröffentlichen" kopiert werden. Das DestinationFiles-Attribut für das Copy-Element ist etwas komplex. Es führt eine Transformation der Elemente durch und konvertiert ihre Pfade in neue Pfade, die im Ordner PublishDestination verwurzelt sind (überprüfen Sie die Metadaten bekannter Elemente, um zu sehen, was diese% () bedeuten).

Um dieses Ziel über die Befehlszeile aufzurufen, können wir jetzt einfach diesen Befehl ausführen (offensichtlich ändern Sie den Namen und die Eigenschaften der Projektdatei entsprechend Ihren Anforderungen):

msbuild Website.csproj "/p:Platform=AnyCPU;Configuration=Release;PublishDestination=F:\Temp\Publish" /t:PublishToFileSystem
P. Roe
quelle
3
Ich kann das Code-Snippet für das neue Ziel nicht verstehen (es zeigt 01 02 03 ...). Könnten Sie bitte bearbeiten?
fan711
2
Ich stimme fan711 zu. Die Lösung wird jedoch auf dem Link beschrieben - wofür sollte sie dann kopiert werden?
Антон Курьян
4
@ АнтонКурьян: Links neigen dazu, nach einiger Zeit zu sterben. Deshalb sollten Fragen und Antworten auf stackoverflow.com immer in sich geschlossen sein, ohne auf externe Ressourcen angewiesen zu sein.
Oliver
Die Ergebnisse sehen so aus, als würde das Veröffentlichungsprofil von MSBuild überhaupt nicht verwendet und stattdessen ein Paket erstellt (möglicherweise eine Standardeinstellung?). Mit der folgenden Lösung wird repliziert, was das Profil tun soll, das von Microsoft.Web.Publishing.targets verarbeitet wird, indem der richtige Typ aus dem Bereitstellungsordner (für FileSystem) ausgewählt wird. Sieht also so aus, als würden Sie das Rad hier neu erfinden, anstatt dieses Problem zu lösen. Aber ohne Ihr MSBuild-Protokoll kann ich das nicht mit Sicherheit sagen. Ich habe meine zum Arbeiten gebracht, Details in meiner Antwort
GregS
1
Die Lösung von GregS funktioniert bei mir nicht. Builds
funktionieren einwandfrei
19

Ich hatte immer noch Probleme, nachdem ich alle oben genannten Antworten ausprobiert hatte (ich verwende Visual Studio 2013). Es wurde nichts in den Veröffentlichungsordner kopiert.

Der Haken war, dass ich, wenn ich MSBuild mit einem einzelnen Projekt anstelle einer Lösung ausführe, einen zusätzlichen Parameter einfügen muss, der die Visual Studio-Version angibt:

/p:VisualStudioVersion=12.0

12.0ist für VS2013, ersetzen Sie durch die Version, die Sie verwenden. Nachdem ich diesen Parameter hinzugefügt hatte, funktionierte es einfach.

Die vollständige Befehlszeile sieht folgendermaßen aus:

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

Ich habe es hier gefunden:

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

Sie geben an:

Wenn Sie anstelle einer Lösung ein einzelnes Projekt angeben, müssen Sie einen Parameter hinzufügen, der die Visual Studio-Version angibt.

felix-b
quelle
12

Mir scheint, dass Ihr Veröffentlichungsprofil nicht verwendet wird und einige Standardverpackungen durchgeführt werden. Die Microsoft Web Publish-Ziele erledigen alles, was Sie oben tun. Sie wählen die richtigen Ziele basierend auf der Konfiguration aus.

Ich habe meine Probleme im TeamCity MSBuild-Schritt problemlos gelöst, aber ich habe einen expliziten Pfad zum Profil angegeben. Sie müssen ihn nur beim Namen ohne .pubxml (z. B. FileSystemDebug) aufrufen. Es befindet sich so lange wie im Standardordner, der Ihnen gehört.

Beispiel:

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

Beachten Sie, dass dies mit den Visual Studio 2012-Versionen der Microsoft Web Publish-Ziele durchgeführt wurde, die sich normalerweise unter "C: \ Programme (x86) \ MSBuild \ Microsoft \ VisualStudio \ v11.0 \ Web" befinden. Überprüfen Sie den Bereitstellungsordner auf die spezifischen Ziele der Bereitstellungstypen, die verwendet werden

GregS
quelle
MS hat viele Verbesserungen vorgenommen, seit dies vor einigen Jahren veröffentlicht wurde. Vielen Dank für die aktualisierte Programmierung.
P. Roe
3

Zu Ihrer Information: Das gleiche Problem beim Ausführen auf einem Build-Server (Jenkins mit installiertem msbuild 15, gesteuert von VS 2017 in einem .NET Core 2.1-Webprojekt).

In meinem Fall war es die Verwendung des "Publish" -Ziels mit msbuild, die das Profil ignorierte.

Also begann mein msbuild Befehl mit:

msbuild /t:restore;build;publish

Dies löste den Veröffentlichungsprozess korrekt aus, aber keine Kombination oder Variation von "/ p: PublishProfile = FolderProfile" hat jemals das Profil ausgewählt, das ich verwenden wollte ("FolderProfile").

Als ich das Veröffentlichungsziel nicht mehr verwendete:

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

Ich dachte (dummerweise), dass es keinen Unterschied machen würde, aber sobald ich den DeployOnBuild-Schalter benutzte, nahm er das Profil korrekt auf.

Aus Orbonia
quelle
2

Eigentlich habe ich alle Ihre Antworten zu meiner eigenen Lösung zusammengeführt, um das obige Problem zu lösen:

  1. Ich erstelle die pubxml-Datei nach meinen Bedürfnissen
  2. Dann kopiere ich alle Parameter aus der pubxml-Datei in meine eigene Parameterliste "/ p: foo = bar" für msbuild.exe
  3. Ich werfe die pubxml-Datei weg

Das Ergebnis ist wie folgt:

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

Rainer
quelle
1

Überprüfen Sie zunächst die Visual Studio-Version des Entwickler-PCs, auf dem die Lösung (das Projekt) veröffentlicht werden kann. wie gezeigt ist für VS 2013

 /p:VisualStudioVersion=12.0

Fügen Sie die obige Befehlszeile hinzu, um anzugeben, welche Art von Visual Studio-Version das Projekt erstellen soll. Wie bereits erwähnt, kann dies passieren, wenn wir versuchen, nur ein Projekt zu veröffentlichen, nicht die gesamte Lösung.

Der vollständige Code wäre also ungefähr so

"C: \ Windows \ Microsoft.NET \ Framework \ v4.0.30319 \ msbuild.exe" "C: \ Programme (x86) \ Jenkins \ Arbeitsbereich \ Jenkinssecondsample \ MVCSampleJenkins \ MVCSampleJenkins.csproj" / T: Build; Package / p : Configuration = DEBUG / p: OutputPath = "obj \ DEBUG" / p: DeployIisAppPath = "Standardwebsite / jenkinsdemoapp" /p:VisualStudioVersion=12.0

Shammie
quelle
1
Tut mir leid, Shammakalubo, du hast die Frage sehr falsch interpretiert.
P. Roe
1
@shammakalubo Die Antwort ist richtig, aber es ist einfach nicht vollständig angegeben. Dieser Parameter muss zu dem vom OP erwähnten Befehl hinzugefügt werden, der dann wie MSBuild C:\PathToMyProject\MyProject.csproj /p:DeployOnBuild=true /p:PublishProfile=MyPublishProfile /p:VisualStudioVersion=12.0folgt lautet : Dieser Parameter hat mir gefehlt und mein Problem behoben. Sie müssen nur die Antwort vollständig erwähnen!
Syed Waqas
@WaqasShah Danke, wie Sie erwähnt haben, habe ich meine Antwort bearbeitet und den vollständigen Code veröffentlicht, wie er aussehen würde.
Shammie