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.

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 Package1systemach 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.configprogramu , a zatem obsługują współzależność dołączania/wykluczania zasobów.

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.configczy 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 metodySuppressDependenciesWhenPackingw 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 PackageReferenceprogramu , 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>/*.dllelementu .

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.LoadMEF 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.dllMyHelpers.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