Teil 2: Funktionalität automatisiert für andere Projekte bereitstellen

NuGet-Pakete debuggen, verteilen und managen
Kommentare

Der Open-Source-Paketmanager NuGet hat sich in der .NET-Welt zur Standardmethode einwickelt, um Funktionalität zwischen mehreren Projekten zu teilen oder öffentlich bereitzustellen – fast jeder Programmierer hat schon ein NuGet-Paket in sein Projekt eingebunden. Doch NuGet kann mehr: Es bietet die Möglichkeit, wichtige Teile des Entwicklungsprozesses innerhalb der eigenen Organisation weiter zu verbessern und zu automatisieren. Im ersten Teil dieser Serie haben wir uns mit dem automatisierten Erstellen von Packages beschäftigt. Im zweiten Teil geht es nun um Debugging und automatisiertes Verteilen der Pakete.

Im ersten Teil dieses Artikels haben wir gesehen, wie NuGet Packages schnell und einfach erstellt werden können. Wie steht es aber mit dem Debugging, wenn diese Pakete in andere Projekte eingebunden werden?

NuGet: Debuggen lokal erstellter Pakete

Haben wir das Paket auf unserem eigenen Rechner erstellt, ist die Sache recht einfach, da die aktuellen Sourcen zu dem Paket lokal vorliegen und vermutlich genau diese Version auch in unser Paket verpackt wurde. Für dieses Szenario genügt es, die .pdb-Datei in das Projekt mit einzufügen. Dazu kann die .nuspec-Datei entsprechend erweitert werden:

<files>
  <file src="$ProjectOutputDir$\MathLib.dll" target="lib\MathLib.dll" />
  <file src="$ProjectOutputDir$\MathLib.pdb" target="lib\MathLib.pdb" />
</files>

Der nuget pack-Befehl besitzt einen Parameter -symbols. Geben wir diesen an (entweder direkt in der Konsole oder in unserer target-Datei), werden zwei Pakete erstellt: eines, in dem nur die dlls enthalten sind und eines, in dem zusätzlich die .pdb-Datei enthalten ist. Wir können das Symbol-Package in unser Repository kopieren und in unserem Anwendungsprojekt aktualisieren.

Debuggen wir nun im Anwendungsprojekt, lässt sich in den Code unseres Packages hineinspringen. Wir sehen, dass die Datei aus dem Source-Pfad unseres Package-Codes angezeigt wird.

Artikelserie

Debuggen von Packages aus TFS Team Build

Wird das Package allerdings von einem Kollegen oder mit TFS Team Build erstellt, funktioniert der oben beschriebene Weg nicht. Hier haben wir als Nutzer des Packages nicht zwingend die Sourcen des Packages in der richtigen Version an der gleichen Stelle auf unserem Entwicklungsrechner. Über unser Package haben wir zwar Zugriff auf die .pdb-Datei, die Codedateien allerdings fehlen uns. Es muss also eine andere Lösung gefunden werden.

Wir brauchen zunächst einen Netzwerk-Share, auf den die Entwickler und TFS Team Build Zugriff haben. In unserer Build-Definition geben wir diesen Pfad unter Path To Publish Symbols an und stellen Index Sources auf True.

Wir erhöhen noch einmal die Versionsnummer in unserer .nuspec-Datei und dieses Mal zudem in der AssemblyInfo.cs, um eine neue Assembly zu erhalten. Anschließend wird alles eingecheckt und der Build getriggert. Danach kopieren wir das Package (nicht das Symbol-Package) in unser Repository und aktualisieren es.

Jetzt werden noch einige Einstellungen in Visual Studio benötigt. Zuerst geben wir den Pfad zu den Symbolen an, den auch TFS Build nutzt (Abb. 1).

Abb. 1: Pfad auf die Symboldateien setzen (in Visual Studio)

Abb. 1: Pfad auf die Symboldateien setzen (in Visual Studio)

Daraufhin aktivieren wir den Source Server Support und deaktivieren die Option Enable Just My Code. Beginnen wir nun mit dem Debuggen, fragt Visual Studio, ob die Quellcodedatei aus der TFS-Versionsverwaltung heruntergeladen werden kann, was wir mit ja bestätigen. Mit Start dieses Prozesses lädt Visual Studio die Datei in den konfigurierten Ordner für den Symbolcache herunter, und wir können unseren Code aus dem Package debuggen, ohne uns selbst darum kümmern zu müssen, wie die passende Version der Sourcedateien heruntergeladen werden kann. Denn die neueste Version aus der Versionsverwaltung passt nicht unbedingt genau zu unserem Paket. Der Symbolserver aber kennt die Version in unserem Package und kann die passende Version der Codedateien von TFS herunterladen. Im Modules-Fenster (Debug/Windows/Modules) lässt sich erkennen, woher der Debugger die Informationen lädt.

Tabelle 1: Modules-Fenster

Tabelle 1: Modules-Fenster


Software Architecture Summit 2017

The Core of Domain-Driven Design

mit Carola Lilienthal (Workplace Solutions)

Distributed Systems

mit Kyle Kingsbury (Independent Consultant)

Packages lokal testen

Wenn ein Package neu entwickelt wird oder Anpassungen (z. B. Bugfixes) gemacht wurden, möchte man das neue Package natürlich erst einmal testen. Dazu sollte es nicht notwendig sein, die Änderungen einzuchecken und zu warten, bis Team Build durchgelaufen ist. Deshalb benötigen wir zwei verschiedene Wege, um unsere Packages zu verteilen (Abb. 2).

Abb. 2: Die Zwei-Repository-Lösung

Abb. 2: Die Zwei-Repository-Lösung

Wir benutzen zwei Repositories: Ein zentrales Repository, das aus TFS Build befüllt wird und über das wir Packages an alle Entwickler verteilen und ein lokales Repository, in dem wir unsere lokalen Build-Packages deployen können, um sie lokal zu testen. Dazu können wir in Visual Studio unter Tools | Options | Package Manager | Package Sources mehrere Repositories konfigurieren.

Hierbei lässt sich die Reihenfolge der Repositories über die Pfeile beeinflussen. Diese Reihenfolge gibt gleichzeitig vor, in welcher Reihenfolge NuGet die Repositories nach einem bestimmten Package durchsucht. Verwendet wird das erste Package mit den angegebenen Suchparametern (ID, Version). Dieses können wir nutzen, um Pakete im lokalen Repository abzulegen und die dort vorhandenen mit einer höheren Priorität zu verwenden, als die Pakete aus dem zentralen Repository. Im Folgenden wird der Vorgang Schritt für Schritt beschrieben:

  1. Wir haben die Consumer Solution geöffnet. Diese benutzt bereits unser Package aus dem Central Repository in der Version 1.0.0. Das lokale Repository ist leer.
  2. Wir analysieren einen Bug und stellen fest, dass dieser in unserem Package liegen muss. Wir öffnen nun in einer zweiten Visual-Studio-Instanz die Package-Solution und passen den Code entsprechend an.
  3. Ein lokaler Build in Visual Studio erzeugt nun das Package. Mit der zuvor beschriebenen Versionierungsmethodik ergibt sich ein Package mit der Version 99.99.99. Wir kopieren das Symbol-Package in unser lokales Repository. Dieser Vorgang kann zum Beispiel durch Post-Build-Event automatisiert werden.
  4. Durch ein einfaches Update wird das Package in der Consumer Solution auf diese Version aktualisiert, und wir können unsere Anpassungen testen und debuggen.
  5. Nachdem wir die Änderungen geprüft und eingecheckt haben, starten wir einen TFS Build. Erzeugt wird nun ein Package mit der nächsthöheren Version, das wir in unser zentrales Repository kopieren.

Um diese Version in unsere Consumer Solution einzubinden, steht ab der Version NuGet 2.8 eine Downgradeoption zur Verfügung, d. h., wir können das Paket aus dem lokalen Repository löschen und die aktuelle Version aus dem zentralen Repository einbinden.

Package-Deployment und Updates

Die einfachste Form, ein eigenes Repository einzurichten, ist die Nutzung eines simplen File-Shares. Eine etwas elegantere Alternative ist der Bau eines NuGet-Servers, was recht einfach geht. Der NuGet-Server hat vor allem den Vorteil, dass man den nuget push-Befehl verwenden kann, um die Packages in das Repository hochzuladen.

Der NuGet-Server wird erstellt, indem man eine leere ASP.NET-Web-Application anlegt und in dieser das Package NuGet Server einbindet. Das Paket bringt alles mit, was benötigt wird. Es fehlen lediglich ein paar Einstellungen in der web.config:

<add key="requireApiKey" value="true"/>
<add key="apiKey" value="1234567890"/> 

Wir können einen Key definieren, der benötigt wird, um Pakete über unseren Server hochzuladen. Dieser kann frei als alphanummerisches Schlüsselwort vergeben werden:

<add key="packagesPath" value=""/>

Standardmäßig werden die Pakete im Ordner „Packages“ innerhalb unseres Webprojekts abgelegt. Mit dieser Einstellung kann ein anderer Ort angegeben werden. Natürlich müssen wir dafür die entsprechenden Berechtigungen auf dem Ordner vergeben:

<add key="allowOverrideExistingPackageOnPush" value="false"/>

In der Regel ist nicht vorgesehen, dass Pakete auf dem Server überschrieben werden können, da dies das Verhalten der Anwendungen verändern könnte, die das Paket konsumieren. Dieses Verhalten kann jedoch auch konfiguriert werden. Wurden diese Einstellungen vorgenommen, können wir den Server kompilieren und deployen. Er kann anschließend direkt genutzt werden. Auf der Startseite finden wir bereits alle Informationen, die wir benötigen, um mit dem Server zu arbeiten.

Wir können nun dafür sorgen, dass unser Build das erstellte Paket automatisch auf dem Server veröffentlicht. Eine einfache Lösung dafür ist eine entsprechende Anpassung unserer NuGet.targets-Datei.

Listing 1
<Target Name="BuildPackageForNuspec" DependsOnTargets="CheckPrerequisites" Inputs="@(Nuget);" Outputs="@(Nuget ->'$(PackageOutputDir)\%(FileName)*.nupkg'">
  <ReadVersionFromAssembly AssemblyFilePath="@(IntermediateAssembly)">
    <Output TaskParameter="AssemblyVersionMajor" PropertyName="AssemblyVersionMajor"/>
    <Output TaskParameter="AssemblyVersionMinor" PropertyName="AssemblyVersionMinor"/>
    <Output TaskParameter="AssemblyVersionBuild" PropertyName="AssemblyVersionBuild"/>
    <Output TaskParameter="AssemblyVersionRevision" PropertyName="AssemblyVersionRevision"/>
  </ReadVersionFromAssembly>
 
  <Exec Command="$(NuGetCommand) pack "@(Nuget)" -o "$(PackageOutputDir)" -p Configuration="$(Configuration)";;ProjectOutputDir="$(PackageOutputDir)";Version=$(AssemblyVersionMajor).$(AssemblyVersionMinor).$(AssemblyVersionBuild) -symbols" />
  <Exec Command="$(NuGetCommand) push "$(PackageOutputDir)\*.nupkg" -s $(NuGetServerUrl) $(NuGetAPIKey)" Condition="'$(PushNuGet)' == 'true'"></Exec>
</Target>

Wir haben hier bereits eine entsprechende Bedingung eingebaut, sodass der push nur ausgeführt wird, wenn der entsprechende Parameter mit true übergeben wird. Den Server-URL und den API-Key haben wir ebenfalls als Parameter ausgeführt, die wir nun im Build übergeben können. Damit wird zum Beispiel erreicht, dass ausschließlich unser TFS-Build einen push ausführt, nicht aber unser lokaler Build bzw. dass wir hier einen anderen Server angeben können. Die MSBuild-Parameter in unserem TFS-Build sehen aus wie in Abbildung 3.

Abb. 3: NuGet-Argumente für die Steuerung des Build-Prozesses

Abb. 3: NuGet-Argumente für die Steuerung des Build-Prozesses

Fazit

Selbermachen lohnt sich: NuGet bietet nicht nur einen bequemen Weg, fremden Code in eigene Projekte einzubinden. Mit etwas MS-Build-Magie wird es zum nützlichen Werkzeug, um Code versionssicher und mit allem Debugging-Komfort zu verteilen – ob „nur“ in der eigenen Organisation oder für die ganze Welt. Viel Spaß dabei!

Windows Developer

Windows DeveloperDieser Artikel ist im Windows Developer erschienen. Windows Developer informiert umfassend und herstellerneutral über neue Trends und Möglichkeiten der Software- und Systementwicklung rund um Microsoft-Technologien.

Natürlich können Sie den Windows Developer über den entwickler.kiosk auch digital im Browser oder auf Ihren Android- und iOS-Devices lesen. In unserem Shop ist der Windows Developer ferner im Abonnement oder als Einzelheft erhältlich.

Aufmacherbild: Shipping, delivery and logistics technology business industrial concept via Shutterstock.com / Urheberrecht: Oleksiy Mark

Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -