30 September 2010 MSBuild HowTo Robert Muehsig

image

Wer Experte in MSBuild ist, der wird über mein Blogpost jetzt nur lächeln können, allerdings für jemanden der bis vor kurzem MSBuild nur von weiten gesehen hat, empfand ich meine Erkenntnisse doch als erleuchtend ;)

Einstieg in MSBuild

Ich werde an dieser Stelle kein großen Einstieg in MSBuild geben. MSBuild ist die Grundlage für den Erstellprozess von .NET Projekten. Thorsten Hans hat eine sehr geniales Tutorial rund um MSBuild gemacht - lesen lohnt sich: Das MSBuild Universum.

Meine Problemstellung

Ich hatte bei mir eine konkrete Problemstelle: In der Firma nutzen wir den TFS 2010 samt den Teambuilds. Hier ein etwas älterer Blogpost, wie wir das damals machten ;)
Nun wollte ich auch auf den Client ein Buildscript haben, mit dem ich alle Solutions (wir haben mehrere - großes Projekt) lokal baut und das Ergebnis in ein Ordner verschiebt. Der TFS macht es ähnlich und verschiebt nach dem erfolgreichen Build alles in die Droplocation. So wollte ich den Teil nachbauen.

Demoprojekte

Meine Demo.sln ist natürlich recht schmall und beinhaltet nur ein ASP.NET MVC Projekt samt Unit Tests - völliger Standard und unverändert:
image

MSBuild

Jetzt kommen wir zu dem sehr simplen, aber effektiven MSBuild:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">
   <PropertyGroup>
		<OutDir>$(MSBuildStartupDirectory)\OutDir\</OutDir>
		<SolutionProperties>
					OutDir=$(OutDir);
					Platform=Any CPU;
					Configuration=Release
		</SolutionProperties>
   </PropertyGroup>
	<ItemGroup>
		<Solution Include="..\MsBuildSample.sln">
			<Properties>
							$(SolutionProperties)
			</Properties>
		</Solution>
	</ItemGroup>
	<Target Name="Build">
		<MSBuild Projects="@(Solution)"/>
	</Target>
</Project>
 

Ganz oben gibt es eine PropertyGroup in dem ich beschreibe, wohin das Ergebnis kopiert wird. Anstatt in den einzelnen Projekten das Ergebnis des Buildvorgangs mir die Sachen in den jeweiligen bin\release Ordnern zu suchen, möchte ich es in mein "OutDir” haben. Ich nutze die MSBuild Property MSBuildStartupDirectory um mir den Ordner des Buildfiles zu ermitteln.

Die "SolutionProperties” beschreiben nur, wie die Solution gebaut werden soll. Also welche Konfiguration (Release/Debug) und überschreibe zudem das OutDir mit meiner eigenen Property.

Danach folgt eine Itemgroup. Ich könnte hier auch mehrere Solutions mit angeben.

Am Ende folgt mein Target "Build”, was auch mein "Default Target” ist (siehe 1. Zeile) - damit weiß ich letztendlich MSBuild an alle Projekte in den angegeben Solutions zu bauen.

Das ganze habe ich unter dem Namen "BuildSolution.build” genannt. Ich nehm an, wenn man es ".target” nennt, dann würde auch die Visual Studio IntelliSense funktionieren, aber man kann es nennen wie man möchte - jedenfalls hab ich keine Einschränkung gemerkt.

Aufruf des Buildscripts

Der Aufruf wäre recht simple z.B. von der Visual Studio 2010 Command Prompt: "msbuild BuildSolution.build”

image

Nach dem Bauen, wird alles in mein OutDir geschoben.

Alles in ein Verzeichnis?

Das stimmt so nicht ganz. Wenn ich Class Libraries baue, dann werden die .dlls in das Verzeichnis verschoben. Was ich aber natürlich nicht will ist, dass wenn ich verschiedene Windows Dienste oder andere Anwendung baue, dass dann alles vermatscht ist. Das gute: Für Webseiten ist das gar kein Problem:

image

Unter _PublishedWebSites findet sich pro Website alle Daten wie man sie benötigt:

image

Für andere Applikationen geht dies mit einem Trick auch. Darüber habe ich hier gebloggt: HowTo: "PublishedApplications” mit MSBuild & dem TFS für Windows Services / DLLs

Feinschliff: Eine Batch Datei

Als kleinen Feinschliff hab ich mir eine Batch Datei gemacht um nicht immer in den Visual Studio Command Prompt zu gehen:

C:\Windows\Microsoft.NET\Framework\v4.0.30319\msbuild.exe Buildsolution.build

Das ganze würde entsprechend auch mit einer anderen .NET Versionsnummer gehen.

Was haben wir nun?

Wir haben einen Script, mit dem wir die 1 + n Solutions bauen können und das Ergebnis in einen Ordner speichern. Durch das batch File könnten man natürlich noch andere Sachen aufrufen, z.B. MSDeploy etc. Auch wenn ich mir da noch nicht ganz sicher bin, wie MSDeploy mit MSBuild zusammenspielt. Ein Ansatz wäre aber das hier.

Wofür mach ich das?

Der Grundgedanke ist folgender: Ich wollte den Prozess, den der TFS mit den TeamBuild auf dem Buildserver macht auch lokal nachstellen. Wenn die kompilierten Dateien in dem Ordner (DropLocation/OutDir) sind, beginn ich meine Deployment-Pakete zusammenzubauen. Wenn ich die Gelegenheit finde und mein Plan richtig in die Tat umgesetzt habe, kann ich darüber ja mal bloggen ;)

Feinschliff die zweite: Die Batch Datei in Visual Studio aufrufen

Ich hab das Buildscript samt der Batch Datei mit in die Solution aufgenommen. Ganz ideal wäre es jetzt noch über ein "Rechtsklick” die Batch auch im Solution Explorer auszuführen:

image

image

Hier ist ein Trick beschrieben mit dem das auch geht:

Ich empfehle an dieser Stelle noch mal Thorsten Hans sein MSBuild Tutorial :)

[ Download Democode ]


Written by Robert Muehsig

Software Developer - from Saxony, Germany - working on primedocs.io. Microsoft MVP & Web Geek.
Other Projects: KnowYourStack.com | ExpensiveMeeting | EinKofferVollerReisen.de