選取專案所參考的組件

元件在建置期間會以兩種不同的方式使用。 第一個是用於編譯,這可讓套件取用者的程式代碼針對元件中的 API 進行編譯,以及讓 Intellisense 提供建議。 第二個是運行時間,其中元件會複製到目錄, bin 並在程式執行期間使用。 有些套件作者想要在編譯時期只想要自己的元件(或其元件的子集),才能供其套件取用者使用,但需要為運行時間提供其所有相依性。 本檔會探討如何達成此結果。

我們建議每個元件有一個套件,而套件相依性則為其他元件。 當 NuGet 還原專案時,它會執行資產選取,並支援包括、排除及建立私人不同的資產類別。 若要防止套件的相依性成為任何人使用套件的編譯時間資產,您可以將資產設為 compile 私用。 在產生的套件中,這會導致 compile 從相依性中排除。 請注意,當未提供任何資產時,預設私人資產為 contentfiles;build;analyzers。 因此,您應該在或 ProjectReference中使用 PrivateAssets="compile;contentfiles;build;analyzers"PackageReference

<ItemGroup>
  <ProjectReference Include="..\OtherProject\OtherProject.csproj" PrivateAssets="compile;contentfiles;build;analyzers" />
  <PackageReference Include="SomePackage" Version="1.2.3" PrivateAssets="compile;contentfiles;build;analyzers" />
</ItemGroup>

如果您要從自訂 nuspec 檔案建立套件,而不是讓 NuGet 自動為您產生套件,您應該 nuspec 使用 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>

這是建議的解決方案有三個原因。

首先,有用的元件通常會由新的元件/套件參考。 雖然公用程式元件可能只供單一封裝使用,因此,如果第二個套件未來想要使用「私用」公用程式元件,則公用程式元件必須移至新的套件,而舊套件需要更新才能將其宣告為相依性, 或公用程式套件必須同時隨附於現有和新的套件中。 如果元件隨附於兩個不同的套件中,而專案會參考這兩個套件,如果兩個套件中有不同版本的公用程式元件,NuGet 將無法協助進行版本管理。

其次,有時候使用套件的開發人員也想要從相依性使用 API。 例如,請考慮套件 Microsoft.ServiceHub.Client 3.0.3078 版。 如果您下載套件並檢查 nuspec 檔案,您可以看到它列出兩個以 Microsoft.VisualStudio. 相依性開頭的套件,這表示它在運行時間需要它們,但它也會排除其編譯資產。 這表示使用 Microsoft.ServiceHub.Client 的專案不會有 IntelliSense 中提供的 Visual Studio API,或者如果他們建置專案,除非專案明確安裝這些套件。 這是具有排除資產的套件相依性的優點。 使用套件的專案,如果他們也想要使用您的相依性,他們可以新增套件的參考,讓 API 可供自己使用。

最後,一些套件作者過去一直對支援多個目標架構之套件的 NuGet 元件選擇感到困惑,因為他們的套件也包含多個元件。 如果您的主要元件支援與公用程式元件不同的目標架構,則可能不清楚要 lib/ 放入所有元件的目錄。 藉由依元件名稱分隔每個套件,每個元件應該進入的資料夾 lib/ 比較直覺。 請注意,這並不表示具有 Package1.net48Package1.net6.0 套件。 這表示 在和中Package1具有 lib/net6.0/Package6.0lib/net48/Package1.dlllib/net5.0/Package2.dlllib/netstandard2.0/Package2.dllPackage2 Nuget 還原專案時,Nuget 會獨立選取這兩個套件的資產。

另請注意,只有使用 PackageReference 的專案才會使用相依性 include/排除資產。 使用 安裝套件 packages.config 的任何專案也會安裝您的相依性,並也有其 API 可供使用。 packages.config 只有 Visual Studio 的舊版 .NET Framework 專案範本才支援。 SDK 樣式專案,即使是以 .NET Framework 為目標的專案也不支援 packages.config,因此支援相依性包含/排除資產。

PackageReferencepackages.config 有不同的功能可供使用。 不論您想要支援使用 PackageReferencepackages.config或兩者的套件取用者,都變更您必須撰寫套件的方式。

NuGet 的 MSBuild 套件目標不支援自動在套件中包含項目參考。 它只會將這些參考的專案列為套件相依性。 GitHub 上有一個問題,其中社群成員會共用其達成此結果的方式,這通常牽涉到使用 PackagePath MSBuild 專案元數據將檔案放在套件中的任何位置,如檔中所述,包括套件中的內容,以及使用 SuppressDependenciesWhenPacking 來避免專案參考成為套件相依性。 也有社群開發的工具可用來作為 NuGet 官方套件的替代方案,其支援此功能。

PackageReference 支援

當套件取用者使用 PackageReference時,NuGet 會獨立選取編譯和運行時間資產,如先前所述。

編譯資產偏好 ref/<tfm>/*.dll (例如 ref/net6.0/*.dll),但如果不存在,則會回復為 lib/<tfm>/*.dll (例如 lib/net6.0/*.dll)。

執行時間資產偏好 runtimes/<rid>/lib/<tfm>/*.dll (例如runtimes/win11-x64/lib/net6.0/*.dll )),但如果不存在,則會回復為 lib/<tfm>/*.dll

由於 ref\<tfm>\ 中的組件不會在執行階段使用,因此它們可以是僅限中繼資料的組件,以便縮減套件大小。

packages.config 支援

使用 packages.config 管理 NuGet 套件的專案,通常會新增對 lib\<tfm>\ 目錄中所有組件的參考。 已新增 ref\ 目錄來支援 PackageReference,因此在使用 packages.config 時不會考慮它。 若要為使用 packages.config 的專案明確地設定參考哪些組件,則套件必須使用 nuspec 檔案中的 <references> 元素。 例如:

<references>
    <group targetFramework="net45">
        <reference file="MyLibrary.dll" />
    </group>
</references>

MSBuild 套件目標不支持 專案 <references> 。 使用 MSBuild 套件時,請參閱 使用 .nuspec 檔案 封裝的檔。

注意

packages.config 專案使用稱為 ResolveAssemblyReference 的處理序來將組件複製到 bin\<configuration>\ 輸出目錄。 會複製您專案的組件,然後建置系統會查看所參考組件的組件資訊清單,然後複製這些組件並以遞迴方式針對所有組件重複執行。 這表示,如果任何只透過反映載入的元件(Assembly.LoadMEF 或其他相依性插入架構),則它可能不會複製到專案的 bin\<configuration>\ 輸出目錄,儘管位於 bin\<tfm>\。 這也表示這隻適用於 .NET 元件,不適用於使用 P/Invoke 呼叫的機器碼。

同時支援 PackageReferencepackages.config

重要

如果套件包含 nuspec <references> 元素,而且不包含 中的 ref\<tfm>\元件,NuGet 會將 nuspec <references> 元素中列出的元件公告為編譯和運行時間資產。 這表示當參考的組件需要載入 lib\<tfm>\ 目錄中任何其他組件時,會有執行階段例外狀況。 因此,請務必同時使用 nuspec <references> 進行 packages.config 支援,以及複製資料夾中的元件 ref/ 以支援 PackageReferenceruntimes/套件資料夾不需要使用,它已新增至上述區段以取得完整性。

範例

我的套件會包含三個組件:MyLib.dllMyHelpers.dllMyUtilities.dll,它們以 .NET Framework 4.7.2 為目標。 MyUtilities.dll 包含的類別只為了供其他兩個組件使用,因此我不想要在 IntelliSense 中提供這些類別,或在編譯時期提供給使用我套件的專案。 我的 nuspec 檔案必須包含下列 XML 元素:

<references>
    <group targetFramework="net472">
        <reference file="MyLib.dll" />
        <reference file="MyHelpers.dll" />
    </group>
</references>

我需要確保我的套件內容如下:

lib\net472\MyLib.dll
lib\net472\MyHelpers.dll
lib\net472\MyUtilities.dll
ref\net472\MyLib.dll
ref\net472\MyHelpers.dll