Was macht NuGet-Paketverwaltung?
Wann dieser Skill verwendet werden sollte
Verwende diesen Skill, wenn:
- NuGet-Pakete hinzugefügt, entfernt oder aktualisiert werden
- Central Package Management (CPM) für eine Projektmappe eingerichtet wird
- Paketversionen über mehrere Projekte hinweg verwaltet werden
- Paketkonflikte oder Wiederherstellungsprobleme behoben werden
Goldene Regel: XML nie direkt bearbeiten
Verwende immer dotnet-CLI-Befehle, um Pakete zu verwalten. Bearbeite niemals manuell .csproj- oder Directory.Packages.props-Dateien.
# RICHTIG: CLI-Befehle verwenden
dotnet add package Newtonsoft.Json
dotnet remove package Newtonsoft.Json
dotnet list package --outdated
# FALSCH: XML direkt bearbeiten
# <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
Warum:
- Die CLI validiert, ob das Paket existiert, und löst die korrekte Version auf
- Verarbeitet transitive Abhängigkeiten korrekt
- Aktualisiert ggf. Sperrdateien (lock files)
- Vermeidet Tippfehler und fehlerhaftes XML
- Funktioniert korrekt mit CPM
Central Package Management (CPM)
CPM zentralisiert alle Paketversionen in einer Datei und vermeidet so Versionskonflikte zwischen Projekten.
CPM aktivieren
Erstelle Directory.Packages.props im Stammverzeichnis der Projektmappe:
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
<PackageVersion Include="Serilog" Version="4.0.0" />
<PackageVersion Include="xunit" Version="2.9.2" />
</ItemGroup>
</Project>
Projektdateien mit CPM
Projekte referenzieren Pakete ohne Versionen:
<!-- src/MyApp/MyApp.csproj -->
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" />
<PackageReference Include="Serilog" />
</ItemGroup>
</Project>
Pakete mit CPM hinzufügen
# Fügt sowohl zu Directory.Packages.props als auch zur Projektdatei hinzu
dotnet add package Serilog.Sinks.Console
# Ergebnis in Directory.Packages.props:
# <PackageVersion Include="Serilog.Sinks.Console" Version="6.0.0" />
# Ergebnis in der Projektdatei:
# <PackageReference Include="Serilog.Sinks.Console" />
Gemeinsame Versionsvariablen
Gruppiere zusammengehörige Pakete mit gemeinsamen Versionsvariablen:
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<!-- Gemeinsame Versionsvariablen -->
<PropertyGroup Label="SharedVersions">
<AkkaVersion>1.5.59</AkkaVersion>
<AkkaHostingVersion>1.5.59</AkkaHostingVersion>
<AspireVersion>9.0.0</AspireVersion>
<OpenTelemetryVersion>1.11.0</OpenTelemetryVersion>
<XunitVersion>2.9.2</XunitVersion>
</PropertyGroup>
<!-- Akka.NET-Pakete – alle verwenden dieselbe Version -->
<ItemGroup Label="Akka.NET">
<PackageVersion Include="Akka" Version="$(AkkaVersion)" />
<PackageVersion Include="Akka.Cluster" Version="$(AkkaVersion)" />
<PackageVersion Include="Akka.Cluster.Sharding" Version="$(AkkaVersion)" />
<PackageVersion Include="Akka.Cluster.Tools" Version="$(AkkaVersion)" />
<PackageVersion Include="Akka.Persistence" Version="$(AkkaVersion)" />
<PackageVersion Include="Akka.Streams" Version="$(AkkaVersion)" />
<PackageVersion Include="Akka.Hosting" Version="$(AkkaHostingVersion)" />
<PackageVersion Include="Akka.Cluster.Hosting" Version="$(AkkaHostingVersion)" />
</ItemGroup>
<!-- Aspire-Pakete -->
<ItemGroup Label="Aspire">
<PackageVersion Include="Aspire.Hosting" Version="$(AspireVersion)" />
<PackageVersion Include="Aspire.Hosting.AppHost" Version="$(AspireVersion)" />
<PackageVersion Include="Aspire.Hosting.PostgreSQL" Version="$(AspireVersion)" />
<PackageVersion Include="Aspire.Hosting.Testing" Version="$(AspireVersion)" />
</ItemGroup>
<!-- OpenTelemetry-Pakete -->
<ItemGroup Label="OpenTelemetry">
<PackageVersion Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="$(OpenTelemetryVersion)" />
<PackageVersion Include="OpenTelemetry.Extensions.Hosting" Version="$(OpenTelemetryVersion)" />
<PackageVersion Include="OpenTelemetry.Instrumentation.AspNetCore" Version="$(OpenTelemetryVersion)" />
<PackageVersion Include="OpenTelemetry.Instrumentation.Http" Version="$(OpenTelemetryVersion)" />
</ItemGroup>
<!-- Testen -->
<ItemGroup Label="Testing">
<PackageVersion Include="xunit" Version="$(XunitVersion)" />
<PackageVersion Include="xunit.runner.visualstudio" Version="$(XunitVersion)" />
<PackageVersion Include="FluentAssertions" Version="6.12.0" />
<PackageVersion Include="Verify.Xunit" Version="26.0.0" />
</ItemGroup>
</Project>
Vorteile:
- Alle Akka-Pakete durch Ändern einer einzigen Variable aktualisieren
- Klare Struktur mit beschrifteten ItemGroups
- Verhindert Versionsabweichungen bei zusammengehörigen Paketen
Wann CPM NICHT verwendet werden sollte
Central Package Management ist nicht immer die richtige Wahl:
Legacy-Projekte
Die Migration einer großen bestehenden Projektmappe zu CPM kann Probleme verursachen:
- Vorhandene Versionskonflikte werden auf einmal sichtbar
- Manche Pakete haben möglicherweise absichtlich unterschiedliche Versionen
- Die Migration erfordert das gleichzeitige Bearbeiten vieler Dateien
Empfehlung: Für Legacy-Projekte entweder inkrementell migrieren oder bei der projektspezifischen Versionierung bleiben, wenn diese funktioniert.
Versionbereiche
CPM erfordert exakte Versionen – es unterstützt keine Versionbereiche:
<!-- NICHT unterstützt mit CPM -->
<PackageVersion Include="Newtonsoft.Json" Version="[13.0,14.0)" />
<!-- Muss exakte Version verwenden -->
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
Wenn Versionbereiche benötigt werden (selten, aber in manchen Bibliotheksszenarien erforderlich), funktioniert CPM nicht.
Ältere .NET-Versionen
CPM erfordert:
- .NET SDK 6.0.300+ oder neuer
- NuGet 6.2+ oder neuer
- Visual Studio 2022 17.2+ oder neuer
Bei Verwendung älterer SDK-Versionen oder wenn Teammitglieder ältere Tools nutzen, kann CPM zu Buildfehlern führen.
Multi-Repo-Lösungen
Wenn Ihre Lösung mehrere unabhängig gebaute Repositorys umfasst, hilft die einzelne Directory.Packages.props von CPM nicht – jedes Repository benötigt seine eigene.
CLI-Befehlsreferenz
Pakete hinzufügen
# Neueste stabile Version hinzufügen
dotnet add package Serilog
# Bestimmte Version hinzufügen
dotnet add package Serilog --version 4.0.0
# Vorabversion hinzufügen
dotnet add package Serilog --prerelease
# Zu bestimmtem Projekt hinzufügen
dotnet add src/MyApp/MyApp.csproj package Serilog
Pakete entfernen
# Aus aktuellem Projekt entfernen
dotnet remove package Serilog
# Aus bestimmtem Projekt entfernen
dotnet remove src/MyApp/MyApp.csproj package Serilog
Pakete auflisten
# Alle Pakete in der Projektmappe auflisten
dotnet list package
# Veraltete Pakete anzeigen
dotnet list package --outdated
# Transitive Abhängigkeiten einbeziehen
dotnet list package --include-transitive
# Verwundbare Pakete anzeigen
dotnet list package --vulnerable
# Veraltete (deprecated) Pakete anzeigen
dotnet list package --deprecated
Pakete aktualisieren
# Mit CPM: Version in Directory.Packages.props bearbeiten
# Dann Wiederherstellung ausführen, um die Änderung zu übernehmen
dotnet restore
# Ohne CPM: Entfernen und mit neuer Version hinzufügen
dotnet remove package Serilog
dotnet add package Serilog --version 4.1.0
# Oder dotnet-outdated-Tool verwenden (empfohlen)
dotnet tool install --global dotnet-outdated-tool
dotnet outdated --upgrade
Wiederherstellung und Bereinigung
# Pakete wiederherstellen
dotnet restore
# Lokalen Cache leeren (Fehlerbehebung)
dotnet nuget locals all --clear
# Erzwungene Wiederherstellung (Cache ignorieren)
dotnet restore --force
Paketquellen
Quellen auflisten
dotnet nuget list source
Privaten Feed hinzufügen
# Authentifizierten Feed hinzufügen
dotnet nuget add source https://pkgs.dev.azure.com/myorg/_packaging/myfeed/nuget/v3/index.json \
--name MyFeed \
--username az \
--password $PAT \
--store-password-in-clear-text
NuGet.config
Für lösungsspezifische Quellen erstelle eine NuGet.config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
<add key="MyPrivateFeed" value="https://pkgs.dev.azure.com/myorg/_packaging/myfeed/nuget/v3/index.json" />
</packageSources>
<packageSourceCredentials>
<MyPrivateFeed>
<add key="Username" value="az" />
<add key="ClearTextPassword" value="%NUGET_PAT%" />
</MyPrivateFeed>
</packageSourceCredentials>
</configuration>
Häufige Muster
Nur-Entwicklungspakete
<!-- Directory.Packages.props -->
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="8.0.0" />
<!-- Projektdatei –Als Entwicklungsabhängigkeit markieren -->
<PackageReference Include="Microsoft.SourceLink.GitHub" PrivateAssets="All" />
Bedingte Pakete
<!-- Nur in Debug-Builds einbinden -->
<ItemGroup Condition="'$(Configuration)' == 'Debug'">
<PackageReference Include="JetBrains.Annotations" />
</ItemGroup>
<!-- Plattformspezifisch -->
<ItemGroup Condition="'$(TargetFramework)' == 'net8.0'">
<PackageReference Include="System.Text.Json" />
</ItemGroup>
Versionsüberschreibung (Notluke)
Wenn CPM für ein Projekt überschrieben werden muss (selten):
<!-- Projektdatei – sparsam verwenden! -->
<PackageReference Include="Newtonsoft.Json" VersionOverride="12.0.3" />
Warnung: Dies wird von Slopwatch erkannt (siehe Skill dotnet/slopwatch) als potenzieller Schlampigkeitscode.
Fehlerbehebung
Versionskonflikte
# Vollständigen Abhängigkeitsbaum anzeigen
dotnet list package --include-transitive
# Herausfinden, was ein bestimmtes Paket anzieht
dotnet list package --include-transitive | grep -i "Paketname"
Wiederherstellungsfehler
# Alle Caches leeren
dotnet nuget locals all --clear
# Wiederherstellung mit detaillierter Protokollierung
dotnet restore --verbosity detailed
# Gesperrte Pakete prüfen
cat packages.lock.json
Sperrdateien
Für reproduzierbare Builds Paketsperrdateien verwenden:
<!-- Directory.Build.props -->
<PropertyGroup>
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
</PropertyGroup>
Anschließend packages.lock.json-Dateien in die Versionskontrolle einchecken.
Anti-Patterns
Nicht: XML direkt bearbeiten
<!-- SCHLECHT: Manuelles XML-Bearbeiten -->
<PackageReference Include="Tippfehler.Paket" Version="1.0.0" />
<!-- Paket existiert möglicherweise nicht! Die CLI würde dies abfangen. -->
Nicht: Inline-Versionen mit CPM
<!-- SCHLECHT: Umgeht CPM -->
<PackageReference Include="Serilog" Version="4.0.0" />
<!-- GUT: Version stammt aus Directory.Packages.props -->
<PackageReference Include="Serilog" />
Nicht: Versionsverwaltung mischen
<!-- SCHLECHT: Manche Versionen in CPM, manche inline -->
<PackageReference Include="Serilog" /> <!-- Aus CPM -->
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> <!-- Inline -->
Nicht: Gemeinsame Variablen vergessen
<!-- SCHLECHT: Zusammengehörige Pakete mit unterschiedlichen Versionen -->
<PackageVersion Include="Akka" Version="1.5.59" />
<PackageVersion Include="Akka.Cluster" Version="1.5.58" /> <!-- Abweichung! -->
<!-- GUT: Gemeinsame Variable verwenden -->
<PackageVersion Include="Akka" Version="$(AkkaVersion)" />
<PackageVersion Include="Akka.Cluster" Version="$(AkkaVersion)" />
Kurzreferenz
| Aufgabe | Befehl |
|---|---|
| Paket hinzufügen | dotnet add package <name> |
| Bestimmte Version hinzufügen | dotnet add package <name> --version <version> |
| Paket entfernen | dotnet remove package <name> |
| Pakete auflisten | dotnet list package |
| Veraltete anzeigen | dotnet list package --outdated |
| Verwundbare anzeigen | dotnet list package --vulnerable |
| Wiederherstellen | dotnet restore |
| Cache leeren | dotnet nuget locals all --clear |
Ressourcen
- Central Package Management: https://learn.microsoft.com/en-us/nuget/consume-packages/central-package-management
- dotnet CLI-Referenz: https://learn.microsoft.com/en-us/dotnet/core/tools/
- NuGet.config-Referenz: https://learn.microsoft.com/en-us/nuget/reference/nuget-config-file