Wybieranie zestawów, do których odwołuje się projekt
Zestawy są używane na dwa różne sposoby podczas kompilacji. Pierwszą z nich jest kompilowanie, która umożliwia kompilowanie kodu użytkownika pakietu względem interfejsów API w zestawie i funkcja IntelliSense w celu udzielenia sugestii. Drugi to środowisko uruchomieniowe, w którym zestaw jest kopiowany do bin
katalogu i jest używany podczas wykonywania programu. Niektórzy autorzy pakietów chcieliby tylko własne zestawy (lub podzbiór zestawów) dostępne dla użytkowników pakietów w czasie kompilacji, ale muszą zapewnić wszystkie ich zależności dla środowiska uruchomieniowego. Ten dokument zawiera informacje na temat sposobów osiągnięcia tego wyniku.
Zalecane: jeden zestaw na pakiet
Naszym zaleceniem jest posiadanie jednego pakietu na zestaw i zależności pakietów do innych zestawów. Gdy program NuGet przywraca projekt, wykonuje wybór zasobów i obsługuje uwzględnianie, wykluczanie i tworzenie prywatnych różnych klas zasobów. Aby zapobiec tworzeniu zasobów czasu kompilacji dla każdego, kto korzysta z pakietu, można utworzyć compile
zasoby prywatne w zależnościach pakietu. W wygenerowanych pakietach spowoduje compile
to wykluczenie z zależności. Należy pamiętać, że domyślne zasoby prywatne, gdy żadna z nich nie jest dostarczana, to contentfiles;build;analyzers
. W związku z tym należy użyć PrivateAssets="compile;contentfiles;build;analyzers"
polecenia w elemecie PackageReference
lub ProjectReference
.
<ItemGroup>
<ProjectReference Include="..\OtherProject\OtherProject.csproj" PrivateAssets="compile;contentfiles;build;analyzers" />
<PackageReference Include="SomePackage" Version="1.2.3" PrivateAssets="compile;contentfiles;build;analyzers" />
</ItemGroup>
Jeśli tworzysz pakiet na podstawie pliku niestandardowego nuspec
, a nie zezwalasz na automatyczne generowanie pakietu NuGet, nuspec
należy użyć atrybutu exclude
XML .
<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>
Istnieją trzy powody, dla których jest to zalecane rozwiązanie.
Po pierwsze, przydatne zestawy często odwołują się do nowych zestawów/pakietów. Chociaż zestaw narzędziowy może być używany tylko przez pojedynczy pakiet dzisiaj, co sprawia, że kuszące do wysłania obu zestawów w jednym pakiecie, jeśli drugi pakiet chce użyć "prywatnego" zestawu narzędziowego w przyszłości, albo zestaw narzędziowy musi zostać przeniesiony do nowego pakietu, a stary pakiet musi zostać zaktualizowany, aby zadeklarować go jako zależność, lub pakiet narzędziowy musi być dostarczony zarówno w istniejącym, jak i nowym pakiecie. Jeśli zestaw jest dostarczany w dwóch różnych pakietach, a projekt odwołuje się do obu pakietów, jeśli istnieją różne wersje zestawu narzędziowego w tych dwóch pakietach, NuGet nie będzie mógł pomóc w zarządzaniu wersjami.
Po drugie, mogą wystąpić czasy, w których deweloperzy korzystający z pakietu chcą również używać interfejsów API z zależności. Rozważmy na przykład pakiet Microsoft.ServiceHub.Client w wersji 3.0.3078. Jeśli pobierzesz pakiet i sprawdzisz nuspec
plik, zobaczysz, że wyświetla on listę dwóch pakietów rozpoczynających się od Microsoft.VisualStudio.
jako zależności, co oznacza, że potrzebuje ich w czasie wykonywania, ale wyklucza również ich zasoby kompilowania. Oznacza to, że projekty korzystające z microsoft.ServiceHub.Client nie będą miały interfejsów API programu Visual Studio dostępnych w funkcji IntelliSense lub jeśli kompilują projekt, chyba że projekt jawnie instaluje te pakiety. I jest to zaleta, że zależność pakietu z elementem zawartości wykluczania ma. Projekty korzystające z pakietu, jeśli chcą również używać zależności, mogą dodać odwołanie do pakietu, aby udostępnić same interfejsy API.
Na koniec niektórzy autorzy pakietów zostali zdezorientowani w przeszłości co do wyboru zestawu NuGet dla pakietów obsługujących więcej niż jedną strukturę docelową, gdy ich pakiet zawiera również wiele zestawów. Jeśli główny zestaw obsługuje różne struktury docelowe zestawu narzędziowego, może nie być oczywiste, do których lib/
katalogów należy umieścić wszystkie zestawy. Oddzielając każdy pakiet według nazwy zestawu, bardziej intuicyjne jest, w których lib/
folderach powinien przechodzić każdy zestaw. Należy pamiętać, że nie oznacza to posiadania Package1.net48
i Package1.net6.0
pakietów. Oznacza to posiadanie lib/net48/Package1.dll
i lib/net6.0/Package6.0
w Package1
systemach i lib/netstandard2.0/Package2.dll
i lib/net5.0/Package2.dll
w Package2
. Po przywróceniu projektu program Nuget będzie niezależnie wykonywać wybór zasobów dla dwóch pakietów.
Należy również pamiętać, że zależność dołączania/wykluczania zasobów jest używana tylko przez projekty przy użyciu funkcji PackageReference. Każdy projekt instalujący pakiet przy użyciu packages.config
programu zainstaluje zależności i ma również dostępne interfejsy API. packages.config
program jest obsługiwany tylko przez starsze szablony projektów programu .NET Framework w programie Visual Studio. Projekty stylu zestawu SDK, nawet te przeznaczone dla platformy .NET Framework, nie obsługują packages.config
programu , a zatem obsługują współzależność dołączania/wykluczania zasobów.
Niezalecane: wiele zestawów w jednym pakiecie
PackageReference
i packages.config
mają dostępne różne funkcje. Niezależnie od tego, czy chcesz obsługiwać użytkowników pakietów korzystających z programu PackageReference
, packages.config
czy obu tych elementów, zmienia sposób tworzenia pakietu.
Element docelowy pakietu MSBuild Pack programu NuGet nie obsługuje automatycznego dołączania odwołań do projektu w pakiecie. Spowoduje to wyświetlenie listy tylko tych przywołynych projektów jako zależności pakietów. W usłudze GitHub występuje problem polegający na tym, że członkowie społeczności udostępnili sposoby osiągnięcia tego wyniku, co zwykle wiąże się z używaniem PackagePath
metadanych elementu MSBuild do umieszczania plików w dowolnym miejscu w pakiecie, zgodnie z opisem w dokumentacji dotyczącej dołączania zawartości w pakiecie i używania metodySuppressDependenciesWhenPacking
w celu uniknięcia, aby uniknąć, aby odwołania do projektu stały się zależnościami pakietów. Istnieją również narzędzia opracowane przez społeczność, które mogą być używane jako alternatywa dla oficjalnego pakietu NuGet, który obsługuje tę funkcję.
PackageReference
Wsparcie
Gdy użytkownik pakietu używa PackageReference
programu , program NuGet wybiera niezależnie kompilowanie i zasoby środowiska uruchomieniowego zgodnie z wcześniejszym opisem.
Skompiluj zasoby preferują ref/<tfm>/*.dll
(na przykład ref/net6.0/*.dll
), ale jeśli tak nie istnieje, nastąpi powrót do lib/<tfm>/*.dll
elementu (na przykład lib/net6.0/*.dll
).
Zasoby środowiska uruchomieniowego wolą runtimes/<rid>/lib/<tfm>/*.dll
(na przykład (runtimes/win11-x64/lib/net6.0/*.dll
)), ale jeśli tak nie istnieje, nastąpi powrót do lib/<tfm>/*.dll
elementu .
Ponieważ zestawy w programie nie są używane w ref\<tfm>\
czasie wykonywania, mogą być zestawami tylko metadanymi , aby zmniejszyć rozmiar pakietu.
packages.config
Wsparcie
Projekty używane packages.config
do zarządzania pakietami NuGet zwykle dodają odwołania do wszystkich zestawów w lib\<tfm>\
katalogu. Katalog ref\
został dodany do obsługi PackageReference
i dlatego nie jest brany pod uwagę podczas korzystania z programu packages.config
. Aby jawnie ustawić, do których zestawów odwołuje się do projektów przy użyciu programu packages.config
, pakiet musi używać <references>
elementu w pliku nuspec. Na przykład:
<references>
<group targetFramework="net45">
<reference file="MyLibrary.dll" />
</group>
</references>
Elementy docelowe pakietu MSBuild nie obsługują <references>
elementu . Zobacz dokumentację dotyczącą pakowania przy użyciu pliku nuspec podczas korzystania z pakietu MSBuild.
Uwaga
packages.config
projekt używa procesu o nazwie ResolveAssemblyReference , aby skopiować zestawy do katalogu wyjściowego bin\<configuration>\
. Zestaw projektu jest kopiowany, a następnie system kompilacji analizuje manifest zestawu dla zestawów, do których odwołuje się zestaw, a następnie kopiuje te zestawy i rekursywnie powtarza dla wszystkich zestawów. Oznacza to, że jeśli którykolwiek z zestawów załadowanych tylko przez odbicie (Assembly.Load
MEF lub inną strukturę iniekcji zależności), może nie zostać skopiowany do katalogu wyjściowego bin\<configuration>\
projektu, mimo że znajduje się w bin\<tfm>\
pliku . Oznacza to również, że działa to tylko w przypadku zestawów platformy .NET, a nie dla kodu natywnego wywoływanego za pomocą wywołania P/Invoke.
Obsługa zarówno, jak PackageReference
i packages.config
Ważne
Jeśli pakiet zawiera element nuspec <references>
i nie zawiera zestawów w ref\<tfm>\
programie , NuGet będzie anonsować zestawy wymienione w elemecie nuspec <references>
jako zasoby kompilowania i środowiska uruchomieniowego. Oznacza to, że wystąpią wyjątki środowiska uruchomieniowego, gdy przywoływalne zestawy muszą załadować dowolny inny zestaw w lib\<tfm>\
katalogu. Dlatego ważne jest, aby używać zarówno narzędzia nuspec <references>
do packages.config
obsługi, jak i duplikowania zestawów w folderze ref/
w celu PackageReference
zapewnienia obsługi. Folder runtimes/
pakietu nie musi być używany, został dodany do powyższej sekcji w celu zapewnienia kompletności.
Przykład
Mój pakiet będzie zawierać trzy zestawy, MyLib.dll
MyHelpers.dll
i MyUtilities.dll
, które są przeznaczone dla programu .NET Framework 4.7.2. MyUtilities.dll
zawiera klasy przeznaczone tylko do użycia przez pozostałe dwa zestawy, więc nie chcę udostępniać tych klas w funkcji IntelliSense ani w czasie kompilacji do projektów przy użyciu mojego pakietu. Mój nuspec
plik musi zawierać następujące elementy XML:
<references>
<group targetFramework="net472">
<reference file="MyLib.dll" />
<reference file="MyHelpers.dll" />
</group>
</references>
Muszę upewnić się, że zawartość pakietu to:
lib\net472\MyLib.dll
lib\net472\MyHelpers.dll
lib\net472\MyUtilities.dll
ref\net472\MyLib.dll
ref\net472\MyHelpers.dll