選取專案所參考的組件
元件在建置期間會以兩種不同的方式使用。 第一個是用於編譯,這可讓套件取用者的程式代碼針對元件中的 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.net48
和 Package1.net6.0
套件。 這表示 在和中Package1
具有 lib/net6.0/Package6.0
lib/net48/Package1.dll
和 lib/net5.0/Package2.dll
lib/netstandard2.0/Package2.dll
。Package2
Nuget 還原專案時,Nuget 會獨立選取這兩個套件的資產。
另請注意,只有使用 PackageReference 的專案才會使用相依性 include/排除資產。 使用 安裝套件 packages.config
的任何專案也會安裝您的相依性,並也有其 API 可供使用。 packages.config
只有 Visual Studio 的舊版 .NET Framework 專案範本才支援。 SDK 樣式專案,即使是以 .NET Framework 為目標的專案也不支援 packages.config
,因此支援相依性包含/排除資產。
不建議:一個套件中的多個元件
PackageReference
和 packages.config
有不同的功能可供使用。 不論您想要支援使用 PackageReference
、 packages.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.Load
MEF 或其他相依性插入架構),則它可能不會複製到專案的 bin\<configuration>\
輸出目錄,儘管位於 bin\<tfm>\
。 這也表示這隻適用於 .NET 元件,不適用於使用 P/Invoke 呼叫的機器碼。
同時支援 PackageReference
和 packages.config
重要
如果套件包含 nuspec <references>
元素,而且不包含 中的 ref\<tfm>\
元件,NuGet 會將 nuspec <references>
元素中列出的元件公告為編譯和運行時間資產。 這表示當參考的組件需要載入 lib\<tfm>\
目錄中任何其他組件時,會有執行階段例外狀況。 因此,請務必同時使用 nuspec <references>
進行 packages.config
支援,以及複製資料夾中的元件 ref/
以支援 PackageReference
。 runtimes/
套件資料夾不需要使用,它已新增至上述區段以取得完整性。
範例
我的套件會包含三個組件:MyLib.dll
、MyHelpers.dll
和 MyUtilities.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