Auswählen von Assemblys, auf die von Projekten verwiesen wird
Assemblys werden während eines Builds auf zwei verschiedene Arten verwendet. Die erste Möglichkeit besteht in der Verwendung für die Kompilierung, wodurch der Code der Paketbenutzer*innen für APIs in der Assembly kompiliert werden, und für das Bereitstellen von Vorschlägen durch IntelliSense. Die zweite Option ist auf die Laufzeit ausgelegt, zu der die Assembly in das bin
-Verzeichnis kopiert und während der Programmausführung verwendet wird. Einige Paketautor*innen möchten, dass ihren Paketbenutzer*innen zur Kompilierzeit nur ihre eigenen Assemblys (oder eine Teilmenge ihrer Assemblys) zur Verfügung stehen, müssen jedoch alle ihre Abhängigkeiten für die Laufzeit bereitstellen. In diesem Dokument werden Möglichkeiten zum Erreichen dieses Ergebnisses behandelt.
Empfohlen: Eine Assembly pro Paket
Es wird empfohlen, ein Paket pro Assembly und Paketabhängigkeiten für andere Assemblys zu verwenden. Wenn NuGet ein Projekt wiederherstellt, wird eine Ressourcenauswahl durchgeführt. Darüber hinaus können Sie verschiedene Ressourcenklassen einschließen, ausschließen oder als „privat“ festlegen. Um zu verhindern, dass die Abhängigkeiten Ihres Pakets zu Kompilierzeitressourcen für Personen werden, die Ihr Paket verwenden, können Sie die Einstellung für compile
-Objekte in „privat“ ändern. Im generierten Paket führt dies dazu, dass compile
aus der Abhängigkeit ausgeschlossen wird. Beachten Sie, dass die Standardeinstellung für private Ressourcen contentfiles;build;analyzers
lautet, wenn kein anderer Wert angegeben ist. Aus diesem Grund sollten Sie PrivateAssets="compile;contentfiles;build;analyzers"
in PackageReference
oder ProjectReference
verwenden.
<ItemGroup>
<ProjectReference Include="..\OtherProject\OtherProject.csproj" PrivateAssets="compile;contentfiles;build;analyzers" />
<PackageReference Include="SomePackage" Version="1.2.3" PrivateAssets="compile;contentfiles;build;analyzers" />
</ItemGroup>
Wenn Sie ein Paket aus einer benutzerdefinierten nuspec
-Datei erstellen, anstatt NuGet automatisch ein Paket für Sie generieren zu lassen, sollte nuspec
das XML-Attribut exclude
verwenden.
<dependencies>
<group targetFramework=".NETFramework4.8">
<dependency id="OtherProject" version="3.2.1" exclude="Compile,Build,Analyzers" />
<dependency id="SomePackage" version="1.2.3" exclude="Compile,Build,Analyzers" />
</group>
</dependencies>
Es gibt drei Gründe, warum dies die empfohlene Lösung ist.
Erstens werden nützliche Assemblys häufig von neuen Assemblys bzw. Paketen referenziert. Obwohl eine Hilfsprogrammassembly aktuell möglicherweise nur von einem einzigen Paket verwendet werden soll, ist es verlockend, beide Assemblys in einem einzelnen Paket zu platzieren. Wenn ein zweites Paket die „private“ Hilfsprogrammassembly in Zukunft verwenden möchte, muss entweder die Hilfsprogrammassembly in ein neues Paket verschoben werden, und das alte Paket muss aktualisiert werden, um es als Abhängigkeit zu deklarieren, oder das Hilfsprogrammpaket muss sowohl im vorhandenen als auch im neuen Paket enthalten sein. Wenn die Assembly in zwei verschiedenen Paketen enthalten ist und ein Projekt auf beide Pakete verweist, kann NuGet die Versionsverwaltung nicht unterstützen, wenn es sich in den beiden Paketen um unterschiedliche Versionen der Hilfsprogrammassembly handelt.
Zweitens kann es vorkommen, dass Entwickler*innen, die Ihr Paket verwenden, auch APIs aus Ihren Abhängigkeiten verwenden möchten. Sehen Sie sich beispielsweise das Paket Microsoft.ServiceHub.Client, Version 3.0.3078 an. Wenn Sie das Paket herunterladen und die nuspec
-Datei überprüfen, erkennen Sie, dass zwei Pakete aufgelistet sind, die mit Microsoft.VisualStudio.
als Abhängigkeiten beginnen. Dies bedeutet, dass sie zur Laufzeit benötigt werden, aber deren Kompilierungsressourcen ausgeschlossen werden. Aus diesem Grund verfügen Projekte, die „Microsoft.ServiceHub.Client“ verwenden, nicht über die in IntelliSense verfügbaren Visual Studio-APIs. Dies gilt auch bei Erstellung des Projekts, es sei denn, das Projekt installiert diese Pakete explizit. Dies ist der Vorteil, den eine Paketabhängigkeit mit einem Ausschlussobjekt hat. Wenn bei Projekten, bei denen Ihr Paket verwendet wird, auch Ihre Abhängigkeiten genutzt werden sollen, können Sie einen Verweis auf das Paket hinzufügen, um die APIs für diese selbst verfügbar zu machen.
Einige Paketautor*innen waren in der Vergangenheit hinsichtlich der Assemblyauswahl von NuGet für Pakete verwirrt, die mehr als ein Zielframework unterstützen, wenn ihr Paket auch mehrere Assemblys enthält. Wenn die Hauptassembly verschiedene Zielframeworks für die Hilfsprogrammassembly unterstützt, ist es möglicherweise nicht offensichtlich, in welchen lib/
-Verzeichnissen alle Assemblys platziert werden sollen. Wenn jedes Paket nach Assemblyname getrennt wird, ist es intuitiver, in welchen lib/
-Ordnern die einzelnen Assemblys platziert werden sollen. Beachten Sie, dass dies nicht bedeutet, dass die Pakete Package1.net48
und Package1.net6.0
genutzt werden. Vielmehr sind lib/net48/Package1.dll
und lib/net6.0/Package6.0
in Package1
bzw. lib/netstandard2.0/Package2.dll
und lib/net5.0/Package2.dll
in Package2
enthalten. Wenn NuGet ein Projekt wiederherstellt, führt NuGet die Ressourcenauswahl für die beiden Pakete unabhängig durch.
Beachten Sie auch, dass Ressourcen zum Einschließen bzw. Ausschließen von Abhängigkeiten nur von Projekten verwendet werden, die „PackageReference“ nutzen. Jedes Projekt, das Ihr Paket mithilfe von packages.config
installiert, installiert Ihre Abhängigkeiten und stellt auch die zugehörigen APIs zur Verfügung. packages.config
wird nur von älteren .NET Framework-Projektvorlagen von Visual Studio unterstützt. Projekte im SDK-Stil (und somit auch auf das .NET Framework ausgerichtete Projekte) bieten keine Unterstützung für packages.config
und unterstützen daher Ressourcen zum Einschließen bzw. Ausschließen von Abhängigkeiten.
Nicht empfohlen: Mehrere Assemblys in einem Paket
PackageReference
und packages.config
umfassen unterschiedliche verfügbare Features. In Abhängigkeit davon, ob Sie Paketbenutzer*innen unterstützen möchten, die PackageReference
, packages.config
oder beides verwenden, ändert sich die Art, wie Sie Ihr Paket erstellen müssen.
Das MSBuild-Paketziel von NuGet unterstützt das Einschließen von Projektverweisen in das Paket nicht automatisch. Diese Projekte, auf die verwiesen wird, werden nur als Paketabhängigkeiten aufgeführt. Es gibt ein Issue auf GitHub, über das Communitymitglieder Möglichkeiten geteilt haben, wie sie dieses Ergebnis erreicht haben. Dazu zählt in der Regel die Verwendung der PackagePath
-MSBuild-Elementmetadaten zum Platzieren von Dateien an einer beliebigen Stelle im Paket (beschrieben in der Dokumentation zum Einschließen von Inhalten in ein Paket) sowie die Verwendung von SuppressDependenciesWhenPacking
, um zu vermeiden, dass die Projektverweise zu Paketabhängigkeiten werden. Es gibt auch von der Community entwickelte Tools, die als Alternative zum offiziellen Paket von NuGet verwendet werden können und dieses Feature unterstützen.
PackageReference
-Unterstützung
Wenn Paketbenutzer*innen PackageReference
verwenden, wählt NuGet wie zuvor beschrieben die Kompilierungs- und Laufzeitressourcen unabhängig voneinander aus.
Kompilierungsressourcen bevorzugen ref/<tfm>/*.dll
(z. B. ref/net6.0/*.dll
), aber wenn dieses Element nicht vorhanden ist, wird stattdessen lib/<tfm>/*.dll
(z. B. lib/net6.0/*.dll
) verwendet.
Laufzeitressourcen bevorzugen runtimes/<rid>/lib/<tfm>/*.dll
(z. B. runtimes/win11-x64/lib/net6.0/*.dll
), aber wenn dieses Element nicht vorhanden ist, wird stattdessen lib/<tfm>/*.dll
verwendet.
Da Assemblys in ref\<tfm>\
nicht zur Laufzeit verwendet werden, kann es sich um reine Metadatenassemblys zum Verringern der Paketgröße handeln.
packages.config
-Unterstützung
Projekte mit Verwendung von packages.config
zum Verwalten von NuGet-Paketen fügen normalerweise Verweise auf alle Assemblys im lib\<tfm>\
-Verzeichnis hinzu. Das ref\
-Verzeichnis wurde hinzugefügt, um PackageReference
zu unterstützen und wird deshalb bei Verwendung von packages.config
nicht berücksichtigt. Um explizit über packages.config
festzulegen, welche Assemblys für Projekte referenziert werden, muss das Paket das <references>
-Element in der nuspec-Datei verwenden. Zum Beispiel:
<references>
<group targetFramework="net45">
<reference file="MyLibrary.dll" />
</group>
</references>
Die MSBuild-Paketziele unterstützen das <references>
-Element nicht. Weitere Informationen zur Verwendung des MSBuild-Pakets finden Sie unter Packen mithilfe einer NUSPEC-Datei.
Hinweis
Das Projekt packages.config
verwendet einen Prozess namens ResolveAssemblyReference, um Assemblys in das Ausgabeverzeichnis bin\<configuration>\
zu kopieren. Ihre Projektassembly wird kopiert, anschließend sucht das Buildsystem im Assemblymanifest nach referenzierten Assemblys und kopiert diese Assemblys. Dieser Vorgang wird rekursiv für alle Assemblys wiederholt. Dies bedeutet Folgendes: Wenn eine der Assemblys nur durch Reflektion geladen wird (Assembly.Load
, MEF oder ein anderes Framework für die Abhängigkeitsinjektion), wird sie möglicherweise nicht in das bin\<configuration>\
-Ausgabeverzeichnis Ihres Projekts kopiert, obwohl sie in bin\<tfm>\
vorhanden ist. Dies bedeutet auch, dass dies nur für .NET-Assemblys funktioniert, nicht für nativen Code, der mit P/Invoke aufgerufen wird.
Unterstützen von PackageReference
und packages.config
Wichtig
Wenn ein Paket das NUSPEC-Element <references>
umfasst und in ref\<tfm>\
keine Assemblys enthält, kündigt NuGet die im NUSPEC-Element <references>
aufgeführten Assemblys sowohl als Kompilierzeit- als auch als Laufzeitressourcen an. Dies bedeutet, dass es zu Laufzeitausnahmen kommt, wenn die referenzierten Assemblys eine andere Assembly im lib\<tfm>\
-Verzeichnis laden müssen. Daher ist es wichtig, sowohl das NUSPEC-Element <references>
für die Unterstützung von packages.config
zu verwenden als auch Assemblys im Ordner ref/
für die Unterstützung von PackageReference
zu duplizieren. Der Paketordner runtimes/
muss nicht verwendet werden. Er wurde aus Gründen der Vollständigkeit dem obigen Abschnitt hinzugefügt.
Beispiel
Das Beispielpaket enthält drei Assemblys – MyLib.dll
, MyHelpers.dll
und MyUtilities.dll
–, die auf .NET Framework 4.7.2 ausgerichtet sind. MyUtilities.dll
enthält Klassen, die nur von den anderen zwei Assemblys verwendet werden sollen, deshalb sollen diese Klassen nicht in IntelliSense oder zur Kompilierzeit für Projekte zur Verfügung stehen, die das Beispielpaket verwenden. Die Datei nuspec
muss folgende XML-Elemente enthalten:
<references>
<group targetFramework="net472">
<reference file="MyLib.dll" />
<reference file="MyHelpers.dll" />
</group>
</references>
Ich muss sicherstellen, dass mein Paket Folgendes umfasst:
lib\net472\MyLib.dll
lib\net472\MyHelpers.dll
lib\net472\MyUtilities.dll
ref\net472\MyLib.dll
ref\net472\MyHelpers.dll