News

Update der .NET Build Projekt Vorlagen für Visual Studio 2008

16.05. 2008

Die Projektvorlagen für die .NET Buildumgebung wurden für Visual Studio 2008 ergänzt. Ausserdem wurde ein Checkout Problem in der Vorlage für Visual Studio 2005 mit SourceSafe behoben.

Weiterlesen …

Neuer Artikel über das Debuggen des .NET Frameworks

04.05. 2008

Ein neuer Artikel über das Debuggen der .NET Framework Basisklassen ist verfügbar.

Weiterlesen …

Newsfeed

Die News sind auch als RSS Feed verfügbar und können mit einem entsprechenden Programm abonniert werden. Wie geht das? Lesen sie mehr dazu auf Wikipedia.

Wissen > Build Umgebung für .NET > Projektaufbau und Konfiguration der Buildumgebung

Projektaufbau und Konfiguration

Der Build Server

Sie sollten wenn irgendwie möglich einen dedizierten Rechner als Build Server vorsehen, und ihn nicht auf einer Entwicklerstation betreiben.
Gründe dafür sind unter anderem das zuverlässigere Setup, die bessere Verfügbarbarkeit und Stabilität und eine wohl definierte Umgebung. Vor allem der letzte Punkt ist auf einem Entwickler PC nicht gegeben.

Das Ziel Setup für den Build Server sieht vor, dass eine neue Umgebung mit minimalem Aufwand eingerichtet werden kann. Die Build Konfiguration jedes einzelnen Projektes ist deshalb komplett im Repository abgelegt. Sie wird nun im Detail besprochen.
Ein neuer Build Server kann ganz einfach in Betrieb genommen werden, indem lediglich CruiseControl.Net und Subversion installiert und die Konfiguration aus dem Repository aufgerufen wird. Die detaillierte Anleitung für die Konfiguration finden sie in der CruiseControl.NET Konfiguration.

Der Entwickler PC

Nebst Visual Studio 2005 oder 2008 und einem Subversion Client oder Visual SourceSafe werden keine weiteren Tools benötigt, um die Build Umgebung bedienen zu können.
Die Installation von Subversion und entsprechenden Clients wird im Artikel Source Code Verwaltung mit Subversion ausführlich besprochen.

Das Repository und Projekt Layout

Einer der wichtigsten CI Aspekte ist es, alle benötigten Projektelemente im Repository aufzunehmen. Dies erlaubt es jedem Entwickler, durch ein simples Abrufen der letzen Version aus dem Repository eine lokale Umgebung zu erhalten, in welcher sofort gearbeitet werden kann. Weil auch alle Werkzeuge im Repository vorhanden sind, erhält der Entwickler ohne weitere Installation und Konfiguration von Komponenten die neuesten Versionen mit den korrekten Abhängigkeiten.

Um dies zu ermöglichen, wird die folgende Verzeichnisstruktur für ein Projekt verwendet:
Builds
    CruiseControl.NET
        server
            ccnet.config
        webdashboard
Deploy
Install

Src
Tools
build.csproj
BuildNumber.txt
Der Ordner Builds wird sämtliche Daten und Reports über die Builds von CruiseControl.NET beinhalten. CCNet wird hier für den ContinuousBuild und den ReleaseBuild je ein weiteres Verzeichnis anlegen.

In Deploy befinden sich die vom ReleasseBuild erstellten Lieferobjekte. Pro Release wird automatisch ein Verzeichnis erstellt.

In Install befinden sich alle Setup Projekte. Diese können entweder mit dem in Visual Studio integrierten Projekt Assistenten angelegt werden, oder sie können auf der frei verfügbaren Microsoft Technologie WiX basieren. Beide Varianten werden vom Build Prozess unterstützt und automatisch mit dem Build kompiliert.

Wenn Sie die in Visual Studio integrierte Projektvorlage für ein MSI basiertes Setup Projekt verwenden, müssen Sie Visual Studio auf dem Build Server installieren. Ein solches Setup Projekt kann nicht einfach via MSBuild kompiliert werden, sondern benötigt das entsprechende Visual Studio Addin.


Im Ordner src befinden sich alle Visual Studio Solutions und Projekte. Diese können wiederum innerhalb Verzeichnissen gegliedert sein, der Build Prozess unterstützt auch hierarchisch aufgebaute Projekt Strukturen in Visual Studio. Dies kann bei einer Solution mit vielen Projekten die Übersicht und Navigation im Code erleichtern.

Im Verzeichnis Tools befinden sich alle vom Build verwendeten Werkzeuge und Utilities. Um Copyright Probleme zu umgehen, und um sicherzustellen, dass sie mit den aktuellen Versionen arbeiten, sind die Tools nicht in der Build Vorlage enthalten, sondern müssen von ihnen von der jeweiligen Website runtergeladen werden. Je nach ihren Anforderungen und Anpassungen des Build Prozesses benötigen sie auch nicht alle Tools. Die Installation wird weiter unten detailliert erklärt.

Es ist empfehlenswert, eine Projekt Struktur aufzubauen, in welcher die Test Projekte klar vom "produktiven" Code getrennt abgelegt sind. Der Build Prozess unterscheidet Test Projekte von produktivem Code anhand des Projektnamens. Dieser muss für ein Testprojekt "UnitTest" im Namen enthalten.
Beispielsweise heisst ein Testprojekt also ACME.BusinessLogic.UnitTest.

Die Datei build.csproj enthält schliesslich die ganze MSBuild Konfiguration mit allen Build Targets und Tasks. Ein Entwickler kann den Build über diese Datei auch lokal starten, in diesem Fall wird die ganze Solution mit allen Projekten erstellt.

Die Datei BuildNumber.txt enthält die fortlaufend nummerierte Build Nummer, welche Bestandteil der Versionsinformation der Assemblies ist. Wie diese Nummer und die Versionsinformationen erstellt werden, wird im ContinuousBuild erklärt.

Tools

Wie oben erwähnt, benötigt das Build Skript einige Tools um gewisse Aufgaben im Build Prozess erledigen zu können. Alle diese Tools werden im Tools Ordner abgelegt und mit dem Projekt im Repository versioniert.

MSBuild Community Tasks

MSBuild bringt von Haus aus bereits einiges an Funktionalität mit. Wenn jedoch Funktionalität wie das Senden eines Emails, der Zugriff auf Source Code Repositories oder anspruchsvollere Dateioperationen gefragt sind, muss MSBuild passen. Eine Möglichkeit wäre, über den Exec Task externe Programme aufzurufen, dies geht jedoch auch nicht in jedem Fall.
Die MSBuild Community Tasks bieten diverse nützliche Tasks an welche MSBuild ideal ergänzen. Der Build Prozess benötigt diese Tasks unter anderem, um auf Subversion zuzugreifen, um die Unit Tests auszuführen und um Vorlagen basiert Dateien zu erzeugen.
Kopieren sie den neuesten verfügbaren Nightly Build und kopieren sie den Inhalt des Build Verzeichnisses in das Tools\MSBuild.Community.Tasks Verzeichnis der Projektvorlage.
Download: http://msbuildtasks.tigris.org/MSBuild.Community.Tasks.Nightly.zip

NUnit

Wenn sie bereits Unit Tests einsetzen, müssen nicht viele Worte über NUnit verloren werden. Installieren sie NUnit und kopieren sie den gesamten Inhalt von c:\ProgramFiles\NUnit 2.4.6 ins Verzeichnis Tools\NUnit der Projektvorlage. Danach können sie NUnit wieder deinstallieren, wenn sie es sonst nicht benötigen.
Download: http://www.nunit.org/index.php?p=download

WiX

Das Windows Installer XML (WiX) Projekt war das erste Projekte von Microsoft das unter einer Open Source Lizenz (CPL) Lizenz veröffentlicht wurde.
Sie können WiX verwenden, um Windows Installer Programme zu erstellen. Die Installer werden über eine XML Datei programmiert, und werden dann von WiX in eine MSI Datei kompiliert.
Für Visual Studio wird eine Projektvorlage mitgeliefert, welche das Editieren und Kompilieren der .wxs Dateien ermöglicht.
Installieren sie WiX und kopieren sie den gesamten Inhalt von c:\ProgramFiles\Windows Installer XML v3 ins Verzeichnis Tools\WiX der Projektvorlage.
Download: ProjectAggregator2-3.0.2925.0.msi, Wix-3.0.2925.0.msi

Build Prozess und MSBuild Targets

Der Build Prozess, oder genauer CruiseControl.NET wird während des Ablaufs einige MSBuild Targets aufrufen. Solche Targets können voneinander abhängig gemacht werden. Wenn also Target C von B, und dieses wiederum von Target A abhängig ist, wird beim Aufruf zuerst A, dann B, und dann erst C ausgeführt.
Das Build Skript beinhaltet einige Definitionslisten und Targets, welche von mehreren anderen Targets genutzt werden. Vor den eigentlichen Targets, welche die Aufgaben unseres Build Ablaufs erledigen, werden nun diese allgemeinen Blöcke beschrieben.

Allgemeine PropertyGroup und ItemGroup Blöcke

PropertyGroup und ItemGroup Blöcke in einem MSBuild Skript dienen dazu, benutzerdefinierte Property oder Item Elemente zu definieren. Diese können danach über ihren Namen im Skript angesprochen und verwendet werden.
Zu Beginn des Build Skriptes werden nun einige solcher Blöcke definiert.


<!-- ASCII constants -->
<PropertyGroup>
    <NEW_LINE>%0D%0A</NEW_LINE>
    <TAB>%09</TAB>
    <DOUBLE_QUOTES>%22</DOUBLE_QUOTES>
    <SPACE>%20</SPACE>
</PropertyGroup>

<!-- Version settings -->
<PropertyGroup>
    <Major>0</Major>
    <Minor>1</Minor>
    <Company>CompanyName</Company>
    <!-- The project name must not contain spaces and illegal path chars -->
    <ProjectName>CITemplate.VS2005.SVN</ProjectName>
</PropertyGroup>

<!-- The developers email addresses -->
<ItemGroup>
  <Developers Include="developer1@company.com;
                       developer2@company.com" />
</ItemGroup>

<!-- Solution folders -->
<PropertyGroup>
    <CodeFolder>$(MSBuildProjectDirectory)\src</CodeFolder>
    <BuildsFolder>$(MSBuildProjectDirectory)\Builds</BuildsFolder>
    <DeployFolder>$(MSBuildProjectDirectory)\Deploy</DeployFolder>
    <InstallFolder>$(MSBuildProjectDirectory)\Install</InstallFolder>
    <ToolsFolder>$(MSBuildProjectDirectory)\Tools</ToolsFolder>
    <UseCommonBinFolder>1</UseCommonBinFolder>
    <BinFolder>bin\$(Configuration)</BinFolder>
    <BinFolder Condition=" '$(UseCommonBinFolder)' == '1' ">$(CodeFolder)\bin</BinFolder>
</PropertyGroup>

<!-- Solution files -->
<PropertyGroup>
    <SolutionFileName>CITemplate.sln</SolutionFileName>
    <SolutionFile>$(CodeFolder)\$(SolutionFileName)</SolutionFile>
    <BuildNumberFile>$(MSBuildProjectDirectory)\BuildNumber.txt</BuildNumberFile>
    <KeyFile>$(CodeFolder)\$(ProjectName)-Key.snk</KeyFile>
    <TestResultFileAppendix>-results.xml</TestResultFileAppendix>
    <AssemblyInfoFile>$(CodeFolder)\AssemblyInfoCommon.cs</AssemblyInfoFile>
    <AssemblyInfoTemplate>$(CodeFolder)\AssemblyInfoCommon.Template.cs</AssemblyInfoTemplate>
    <InstallBuildEmailFile>$(TEMP)\BuildEmailFile.htm</InstallBuildEmailFile>
    <InstallBuildEmailTemplate>$(InstallFolder)\BuildEmail.Template.htm</InstallBuildEmailTemplate>
    <WixSolutionFileName>$(InstallFolder)\CITemplateAppSetup.sln</WixSolutionFileName>
</PropertyGroup>

<!-- Environment settings -->
<PropertyGroup>
    <SmtpServer>mail.company.com</SmtpServer>
    <BuildServer>build.company.com</BuildServer>
    <BuildMasterMail>buildmaster@company.com</BuildMasterMail>
    <CCNetInstallPath Condition=" '$(CCNetInstallPath)' == '' ">$(ProgramFiles)\CruiseControl.NET</CCNetInstallPath>
    <DeployShare>\\$(BuildServer)\ProjectDeployShare</DeployShare>
</PropertyGroup>

<!-- Tools settings -->
<PropertyGroup>
    <SubversionPath>C:\Program Files\Subversion\bin</SubversionPath>
    <SubversionCmd>$(SubversionPath)\svn.exe</SubversionCmd>
    <NUnitPath>$(ToolsFolder)\NUnit\bin\</NUnitPath>
    <NUnitCmd>$(NUnitPath)nunit-console.exe</NUnitCmd>
    <MSBuildCommunityTasksPath>$(ToolsFolder)\MSBuild.Community.Tasks</MSBuildCommunityTasksPath>
    <WixPath>$(ToolsFolder)\WiX\bin\</WixPath>
    <WixTargetsPath>$(WixPath)Wix.targets</WixTargetsPath>
    <WixTasksPath>$(WixPath)WixTasks.dll</WixTasksPath>
    <WixToolPath>$(WixPath)</WixToolPath>
</PropertyGroup>

<!-- Subversion settings -->
<PropertyGroup>
    <SvnServer>localhost</SvnServer>
    <SvnProjectPath>CITemplate.VS2005.SVN</SvnProjectPath>
    <SvnServerPath>svn://$(SvnServer)/$(SvnProjectPath)</SvnServerPath>
    <SvnTrunkFolder>$(SvnServerPath)/trunk</SvnTrunkFolder>
    <SvnTagsFolder>$(SvnServerPath)/tags</SvnTagsFolder>
</PropertyGroup>

<!-- Setting *.csproj project settings, when none are specified -->
<PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
    <OutputPath Condition=" '$(OutputPath)' == '' ">$(BinFolder)</OutputPath>
    <WixOutputPath Condition=" '$(WixOutputPath)' == '' ">$(InstallFolder)\bin</WixOutputPath>
</PropertyGroup>
Im Block <-- ASCII constants --> werden einige oft verwendete ASCII Zeichen XML codiert definiert.

Im Block <-- Version settings... --> werden die Informationen zur Assembly Versionierung definiert. Eine .NET Assembly Versionsnummer wird nach dem Muster Major.Minor.Build.Revision angegeben.
Setzen sie Versionsnummern für den Major und Minor Teil im Build Skript. Im Feld CompanyName können sie ihren Firmennamen eintragen, er wird ins Assembly Attribut [assembly: AssemblyCompany("CompanyName") eingetragen.
Der Inhalt des Properties ProductName wird ins Assembly Attribut [assembly: AssemblyProduct("ProductName") eingetragen.
Sie können alle diese Assembly Metadaten anschauen, indem sie die Dateieigenschaften einer DLL anzeigen.

Der Abschnitt <-- The developers email addresses --> enthält alle Email Adressen der beteiligten Entwickler. An diese Adressen wird später ein Email mit dem Build Status geschickt.

Im Block <-- Solution folders --> werden die Pfade zu den vorher erläuterten Ordnern unserer Build Vorlage definiert. Wenn ihr Build Ablauf weitere Verzeichnisse benötigt, sollten sie sie hier definieren.
Erwähnenswert ist das hier verwendete Property $(MSBuildProjectDirectory). Der Wert dieses Properties ist immer auf den Ordnerpfad des Build Skriptes gesetzt. Dieses Property ist eines der vordefinierten Properties von MSBuild, welche sie in ihren Skripten ganz einfach mit dem Syntax $(PropertyName) verwenden können.
Wenn sie alle Assemblies zentral in den Ordner src\bin kopiert haben wollen, setzen sie das Property $(UseCommonBinFolder) auf 1. Wenn der Wert auf 0 gesetzt wird, befinden sich alle Assemblies in den jeweiligen Projektverzeichnissen (bin\Debug oder bin\Release).

Der Abschnitt <-- Solution files --> setzt die Pfade zu allen im Build Ablauf verwendeten Dateien. Hier müssen sie den Namen der Visual Studio Solution und ggf. das Key File an ihr Projekt anpassen.

Der Abschnitt <-- Environment settings --> definiert Properties wie den Build Server Namen, den SMTP Server und ein paar andere verwendete Bezeichner. Passen sie diese Werte gemäss ihrer Umgebung an.

Im Block <-- Tools settings --> werden die Pfade zu den Utilities im Tools Ordner gesetzt. Hier brauchen sie nichts zu verändern, eigene Tools, welche sie im Build vewenden wollen, können sie hier referenzieren.

Der Abschnitt <-- Subversion settings --> definiert Properties, mit welchen auf das Source Code Repository zugegriffen wird. Definieren sie hier den Hostnamen ihres Subversion Servers, und den Pfad zu ihrem Projekt im Repository.

Die Definitionsliste <-- Setting *.csproj project... --> setzt einige Standard Properties für das Kompilieren, falls sie noch nicht definiert sind. Diese Properties werden im Aufruf von CruiseControl.NET gesetzt.


<!-- Imports -->
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="$(MSBuildCommunityTasksPath)\MSBuild.Community.Tasks.Targets"/>

<!-- Add the CleanSolution task to the general MSBuild Clean target -->
<PropertyGroup>
    <CleanDependsOn>$(CleanDependsOn);CleanSolution</CleanDependsOn>
</PropertyGroup>
Nun folgen die Import Definitionen der MSBuild Targets. MSBuild wird mit mehreren .targets-Dateien ausgeliefert, die Elemente, Properties, Targets und Tasks für allgemeine Szenarien enthalten. Auch für jede Erweiterung wie die MSBuild Community Tasks gibt es jeweils eine solche .targets Datei. Nach der Import Definition können diese Tasks und Definitionen nun verwendet werden.

Die letzte PropertyGroup überschreibt das Property $(CleanDependsOn). Das Clean Target in Microsoft.CSharp.targets ist abhängig von den Targets, welche in diesem Property eingetragen sind. Wir fügen unser eigenes Target "CleanSolution" hinzu, es wird im ContinuousBuild erklärt.