使用 <PackageReference>
MSBuild 專案的套件參考,直接在專案檔內指定 NuGet 套件相依性,而不是有個別 packages.config
的檔案。 使用 PackageReference 不會影響 NuGet 的其他層面。例如,NuGet.Config 檔案中的設定(包括套件來源)仍會套用,如 常見的 NuGet 組態 中所述。
使用 PackageReference,您也可以使用 MSBuild 條件來選擇每個目標架構的套件參考或其他群組。 它也允許對相依性和內容流動進行細微控制。 (如需詳細資訊,請參閱 NuGet pack and restore as MSBuild targetsNuGet (NuGet 以 pack 與 restore 作為 MSBuild 目標)。)
專案類型支援
根據預設,PackageReference 會用於以 Windows 10 組建 15063 (Creators Update) 及更新版本為目標的 .NET Core 專案、.NET Standard 專案和 UWP 專案 (C++ UWP 專案除外)。 .NET Framework 專案支援 PackageReference,但目前預設為 packages.config
。 若要使用 PackageReference,請將相依性從 packages.config 遷移到您的專案檔,然後移除 packages.config。
以完整的 .NET Framework 為目標的 ASP.NET 應用程式僅包含 PackageReference 的有限支援 \(英文\)。 不支援 C++ 和 JavaScript 專案類型。
新增 PackageReference
使用下列語法在專案檔中新增相依性:
<ItemGroup>
<!-- ... -->
<PackageReference Include="Contoso.Utility.UsefulStuff" Version="3.6.0" />
<!-- ... -->
</ItemGroup>
控制相依性版本
指定套件版本的慣例和使用 packages.config
時一樣:
<ItemGroup>
<!-- ... -->
<PackageReference Include="Contoso.Utility.UsefulStuff" Version="3.6.0" />
<!-- ... -->
</ItemGroup>
在上述範例中,3.6.0 表示任何版本 =3.6.0,>具有最低版本的喜好設定,如套件版本控制中所述。
針對沒有套件相依性的專案使用 PackageReference
進階:如果專案中未安裝任何套件 (專案檔中沒有 PackageReference,也沒有 packages.config 檔案),但希望專案能還原為 PackageReference 樣式,您可以在您的專案檔中將專案屬性 RestoreProjectStyle 設為 PackageReference。
<PropertyGroup>
<!--- ... -->
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
<!--- ... -->
</PropertyGroup>
如果您的參考專案為 PackageReference 樣式 (現有的 csproj 或 SDK 樣式專案),這會很有用。 這會讓這些專案參考的套件成為您專案「過渡性」參考的套件。
PackageReference 和來源
在 PackageReference 專案中,可轉移的相依性版本會在還原時解析。 因此,在 PackageReference 專案中,所有來源都必須可供所有還原使用。
浮動版本
浮動版本支援 PackageReference
:
<ItemGroup>
<!-- ... -->
<PackageReference Include="Contoso.Utility.UsefulStuff" Version="3.6.*" />
<PackageReference Include="Contoso.Utility.UsefulStuff" Version="3.6.0-beta.*" />
<!-- ... -->
</ItemGroup>
控制相依性資產
您可能純粹使用相依性作為開發載入器,不想要對取用套件的專案公開。 在此案例中,您可以使用 PrivateAssets
中繼資料控制這個行為。
<ItemGroup>
<!-- ... -->
<PackageReference Include="Contoso.Utility.UsefulStuff" Version="3.6.0">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<!-- ... -->
</ItemGroup>
以下的中繼資料標籤管理相依性資產:
標記 | 描述 | 預設值 |
---|---|---|
包含資產 | 這些資產將被消耗 | 全部 |
排除資產 | 這些資產不會被消耗 | none |
私人資產 | 這些資產將被使用,但不會流向父專案 | 內容檔案;分析器;建置 |
這些標記的可允許值如下,使用分號隔開多個值,但 all
和 none
必須單獨出現:
值 | 描述 |
---|---|
編譯 | lib 資料夾的內容,以及專案是否能對該資料夾內的組件進行編譯的控制項 |
執行階段 |
lib 和 runtimes 資料夾的內容,以及控制是否將這些組件複製到構建輸出目錄的設定。 |
內容檔案 |
contentfiles 資料夾的內容 |
建立 | .props 和 .targets 在 build 資料夾中 |
buildMultitargeting | (4.0).props 和 .targets 文件,位於 buildMultitargeting 資料夾中,用於跨架構目標的設定 |
buildTransitive | (5.0+).props 和 buildTransitive 在 .targets 資料夾中,適用於可轉移至任何取用專案的資產。 請參閱功能頁面。 |
分析器 | .NET 分析器 |
本地 |
native 資料夾的內容 |
none | 以上皆不使用。 |
全部 | 以上全部 (除了none ) |
<ItemGroup>
<!-- ... -->
<!-- Everything except the content files will be consumed by the project -->
<!-- Everything except content files and analyzers will flow to the parent project-->
<PackageReference Include="Contoso.Utility.UsefulStuff" Version="3.6.0">
<IncludeAssets>all</IncludeAssets> <!-- Default is `all`, can be omitted-->
<ExcludeAssets>contentFiles</ExcludeAssets>
<PrivateAssets>contentFiles;analyzers</PrivateAssets>
</PackageReference>
<!-- ... -->
<!-- Everything except the compile will be consumed by the project -->
<!-- Everything except contentFiles will flow to the parent project-->
<PackageReference Include="Contoso.Utility.SomeOtherUsefulStuff" Version="3.6.0">
<ExcludeAssets>compile</ExcludeAssets>
<PrivateAssets>contentFiles</PrivateAssets>
</PackageReference>
<!-- ... -->
</ItemGroup>
請注意,因為 build
不隨附於 PrivateAssets
,所以目標與屬性會流向父專案。 例如,考慮到上述參考會用在建置名為 AppLogger 之 NuGet 套件的專案中。 AppLogger 和使用 AppLogger 的專案都可以從 Contoso.Utility.UsefulStuff
取用目標與 props。
注意
當在 file
中將 developmentDependency
設定為 true
時,即可將套件標示為僅限開發的相依性,以防止該套件被包含為其他套件的相依性。 使用 PackageReference (NuGet 4.8+) 時,此旗標也表示它在編譯時會排除編譯時間資產。 如需詳細資訊,請參閱 PackageReference 的開發相依性支援。
新增 PackageReference 條件
您可以使用條件來控制是否包含套件,這些條件可以使用任何 MSBuild 變數或在目標或 props 檔案中定義的變數。 但目前僅支援 TargetFramework
變數。
例如,假設您同時以 netstandard1.4
和 net452
為目標,但有一個相依性僅適用於 net452
。 在此情況下,您不希望取用您套件的 netstandard1.4
專案添加不必要的相依性。 為避免這個問題,您需要在 PackageReference
指定條件,如下所示:
<ItemGroup>
<!-- ... -->
<PackageReference Include="Newtonsoft.Json" Version="9.0.1" Condition="'$(TargetFramework)' == 'net452'" />
<!-- ... -->
</ItemGroup>
使用此專案組建的套件將顯示 Newtonsoft.Json 作為相依性隨附,但僅適用於 net452
目標:
以 VS2017 將條件套用於 PackageReference 的結果
條件也可以套用在ItemGroup
層級,並且套用至所有子元素PackageReference
:
<ItemGroup Condition = "'$(TargetFramework)' == 'net452'">
<!-- ... -->
<PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
<PackageReference Include="Contoso.Utility.UsefulStuff" Version="3.6.0" />
<!-- ... -->
</ItemGroup>
生成路徑屬性
這項功能適用於 NuGet 5.0 或更新版本,以及 Visual Studio 2019 16.0 或更新版本。
有時候,可能需要從 MSBuild 目標參考位於套件中的檔案。
在 packages.config
為基礎的專案中,套件會安裝在相對於專案檔的資料夾中。 不過,在 PackageReference 中,套件會從 global-packages 資料夾中使用,該資料夾的位置可能因電腦而異。
為了彌補此差距,NuGet 引入了一個屬性,該屬性指向套件將被使用的位置。
範例:
<ItemGroup>
<PackageReference Include="Some.Package" Version="1.0.0" GeneratePathProperty="true" />
</ItemGroup>
<Target Name="TakeAction" AfterTargets="Build">
<Exec Command="$(PkgSome_Package)\something.exe" />
</Target>
此外,NuGet 會自動為包含工具資料夾的套件產生屬性。
<ItemGroup>
<PackageReference Include="Package.With.Tools" Version="1.0.0" />
</ItemGroup>
<Target Name="TakeAction" AfterTargets="Build">
<Exec Command="$(PkgPackage_With_Tools)\tools\tool.exe" />
</Target>
MSBuild 屬性與套件識別沒有相同的限制,因此套件識別必須改為符合 MSBuild 的易記名稱,名稱前需要加上字串 Pkg
。
若要確認產生的屬性確切名稱,請查看產生的 nuget.g.props 檔案。
PackageReference 別名
在某些罕見的實例中,不同的套件會包含相同命名空間中的類別。 從 NuGet 5.7 和 Visual Studio 2019 Update 7 開始,PackageReference 支援與 ProjectReference 相同的功能 Aliases
。
根據預設,不會提供別名。 指定別名時,所有來自註解套件的元件必須使用別名進行參考。
您可以查看 NuGet\Samples 的範例用法。
在項目檔中,指定別名,如下所示:
<ItemGroup>
<PackageReference Include="NuGet.Versioning" Version="5.8.0" Aliases="ExampleAlias" />
</ItemGroup>
並在程式碼中使用,以下是使用方式:
extern alias ExampleAlias;
namespace PackageReferenceAliasesExample
{
...
{
var version = ExampleAlias.NuGet.Versioning.NuGetVersion.Parse("5.0.0");
Console.WriteLine($"Version : {version}");
}
...
}
NuGet 警告和錯誤
這項功能適用於 NuGet 4.3 或更新版本,以及 Visual Studio 2017 15.3 或更新版本。
對於許多套件打包和還原的情境,所有 NuGet 警告和錯誤都會編碼,並以NU****
開頭。 所有 NuGet 警告和錯誤都會列在 參考 文檔中。
NuGet 會觀察下列警告屬性:
-
TreatWarningsAsErrors
,將所有警告視為錯誤 WarningsAsErrors
,將特定類型的警告視為錯誤NoWarn
,隱藏整個專案或全封裝的特定警告。
範例:
<PropertyGroup>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
...
<PropertyGroup>
<WarningsAsErrors>$(WarningsAsErrors);NU1603;NU1605</WarningsAsErrors>
</PropertyGroup>
...
<PropertyGroup>
<NoWarn>$(NoWarn);NU5124</NoWarn>
</PropertyGroup>
...
<ItemGroup>
<PackageReference Include="Contoso.Package" Version="1.0.0" NoWarn="NU1605" />
</ItemGroup>
隱藏 NuGet 警告
雖然建議您在套件和還原作業期間解決所有 NuGet 警告,但在某些情況下,隱藏這些警告是合理的。 若要在整個專案中抑制警告,請考慮執行:
<PropertyGroup>
<PackageVersion>5.0.0</PackageVersion>
<NoWarn>$(NoWarn);NU5104</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Contoso.Package" Version="1.0.0-beta.1"/>
</ItemGroup>
有時警告僅適用於圖形中的特定套件。 我們可以選擇在 PackageReference 項目上新增 NoWarn
,以更選擇性地隱藏該警告。
<PropertyGroup>
<PackageVersion>5.0.0</PackageVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Contoso.Package" Version="1.0.0-beta.1" NoWarn="NU1603" />
</ItemGroup>
隱藏 Visual Studio 中的 NuGet 套件警告
在 Visual Studio 中,您也可以透過 IDE 抑制警告。
鎖定相依性
此功能在 NuGet 4.9 或更高版本以及 Visual Studio 2017 15.9 或更高版本中可用。
NuGet 還原的輸入是項目檔中的一組 PackageReference
項目(頂層或直接依賴),輸出是所有套件依賴的完整閉包,包括傳遞依賴。 若輸入 PackageReference 清單未變更,NuGet 會嘗試一律產生相同的完整套件相依性封閉。 不過,在一些情況下,無法這樣做。 例如:
當您使用像
<PackageReference Include="My.Sample.Lib" Version="4.*"/>
這樣的浮動版本時。 雖然這裡的目的是在每次套件還原時浮動到最新版本,但在某些情況下,使用者需要圖形鎖定到特定的最新版本,並在可用時通過明確的操作浮動到更高版本。會發行符合 PackageReference 版本需求的的較新套件版本。 例如
第 1 天:如果您指定了 , 但 NuGet 存放庫上可用的版本是 4.1.0、4.2.0 和 4.3.0。 在此案例中,NuGet 會將版本解析為 4.1.0 (最接近的最低版本)
第 2 天:版本 4.0.0 發行。 NuGet 現在將會找到精確匹配,並開始解析到 4.0.0
給定套件版本會從存放庫移除。 雖然 nuget.org 不允許刪除套件,但並非所有套件存放庫都有此條件約束。 這會導致 NuGet 在無法解析為已刪除的版本時尋找最佳相符項目。
啟用鎖定檔案
若要維持套件相依性的完整閉合,您可以透過在專案中設定 MSBuild 屬性 RestorePackagesWithLockFile
來選擇啟用鎖定檔案功能:
<PropertyGroup>
<!--- ... -->
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
<!--- ... -->
</PropertyGroup>
若已設定此屬性,NuGet 還原將在專案根目錄中產生一個鎖定檔案—packages.lock.json
檔案,該檔案會列出所有的套件相依性。
注意
一旦專案的根目錄中有packages.lock.json
檔案,鎖定檔案就會一律用於還原,即使未設定RestorePackagesWithLockFile
屬性也是如此。 因此,另一種啟用此功能的方法是在專案的根目錄中建立一個空白的虛擬 packages.lock.json
檔案。
restore
檔案鎖定行為
若此專案有鎖定檔案存在,NuGet 會使用此鎖定檔案來執行 restore
。 NuGet 會執行快速檢查以查看套件相依性中是否有變更,如專案檔 (或相依專案的檔案) 所述,而且若沒有變更,它只會還原鎖定檔案中所述的套件。 不會重新評估套件相依性。
若 NuGet 偵測到定義相依性中的變更 (如專案檔中所述),它會重新評估套件圖表並更新鎖定檔案以反映專案的新套件終止。
針對 CI/CD 與其他案例,若不想即時變更套件相依性,您可以將 lockedmode
設定為 true
:
針對 dotnet.exe,請執行:
> dotnet.exe restore --locked-mode
針對 msbuild.exe,請執行:
> msbuild.exe -t:restore -p:RestoreLockedMode=true
您也可以在您的專案檔中設定此條件式 MSBuild 屬性:
<PropertyGroup>
<!--- ... -->
<RestoreLockedMode>true</RestoreLockedMode>
<!--- ... -->
</PropertyGroup>
若鎖定模式為 true
,還原操作將會復原鎖定檔案中列出的精確套件;如果您在鎖定檔案建立後更新了專案的已定義套件相依性,還原操作將失敗。
讓鎖定檔案成為您來源存放庫的一部分
如果您正在建置應用程式和可執行檔,且該專案位於相依鏈的起始位置,請將鎖定檔案提交到原始程式碼存放庫,這樣 NuGet 可以在還原期間使用它。
不過,若您的專案是您不會發行的程式庫專案,或是其他專案所相依的一般程式碼專案,您不應該將鎖定檔案提交作為您原始程式碼的一部分。 保留鎖定檔案並不會造成傷害,但在還原/建置相依於此一般程式碼專案的專案時,無法使用一般程式碼專案的鎖定套件相依性,如鎖定檔案中所列。
例如:
ProjectA
|------> PackageX 2.0.0
|------> ProjectB
|------>PackageX 1.0.0
若 ProjectA
對 PackageX
版本 2.0.0
有相依性,且參考了相依於 PackageX
版本 1.0.0
的 ProjectB
,則 ProjectB
的鎖定檔案將會列出對 PackageX
版本 1.0.0
的相依性。 不過,當ProjectA
建置時,其鎖定檔案會包含對PackageX
的版本2.0.0
的依賴性,而不是版本1.0.0
,如ProjectB
的鎖定檔案中所列。 因此,一般程式碼專案的鎖定檔案對於相依於它之專案的解析套件沒有多大決定權。
鎖檔案的可擴充性
您可以使用鎖定文件控制還原的各種行為,如下所述:
NuGet.exe選項 | dotnet 選項 | MSBuild 同等選項 | 描述 |
---|---|---|---|
-UseLockFile |
--use-lock-file |
使用鎖檔案還原套件 | 選擇啟用鎖定檔案。 |
-LockedMode |
--locked-mode |
恢復鎖定模式 | 將鎖定模式啟用於還原作業。 這在您想要可重複建置的 CI/CD 案例中很有用。 |
-ForceEvaluate |
--force-evaluate |
RestoreForceEvaluate | 對於專案中已定義浮動版本的套件而言,此選項非常實用。 根據預設,除非您使用此選項執行還原,否則 NuGet 還原不會在每個還原時自動更新套件版本。 |
-LockFilePath |
--lock-file-path |
NuGetLockFilePath | 為專案定義自訂鎖定檔案位置。 預設情況下,NuGet 支援根目錄的 packages.lock.json 。 若您在相同目錄中有多個專案,NuGet 支援針對專案的特定鎖定檔案,例如 packages. |
NuGet 相依性解析程式
NuGet 相依性解析程式遵循4個規則,如相依性解析文件中所述。
為了改善還原作業的效能和延展性,還原演算法會在 6.12 版本中重寫。
自 6.12 版起,預設會為所有 PackageReference 項目啟用新的還原演算法。
雖然新的還原演算法在功能上相當於先前的演算法,但與任何軟體一樣,Bug 是可能的。
若要還原為先前的實作,請將 MSBuild 屬性 RestoreUseLegacyDependencyResolver
設定為 true
。
如果您在 6.12 版本、.NET 9 版本或 17.12 版本中遇到無法在舊版中重現的還原失敗,請在 GitHub 上提出問題。 舊演算法與新演算法之間的任何差異可能會有不同的影響,例如在編譯期間或運行時間。 還有可能變更不會導致失敗,而是還原不同的套件版本。 如果您認為您可能會受到任何變更的影響,以下是您可以採取的步驟來確認 NuGet 還原演算法中的變更是否為根本原因。
復原將其結果寫入 MSBuildProjectExtensionsPath
目錄,可以與新舊演算法進行比較以找出差異。
這通常是 obj
你建置的資料夾。
您可以使用 msbuild.exe
或 dotnet.exe
進行後續步驟。
- 移除項目的
obj
資料夾。 - 執行
msbuild -t:restore
- 將
obj
的內容儲存到標示為new
行為的位置。 - 執行
msbuild -t:restore -p:RestoreUseLegacyDependencyResolver="true"
- 將
obj
的內容儲存到指示為legacy
行為的位置。 - 比較兩個目錄中的檔案,特別是 project.assets.json。 特別適合用來顯示差異的工具(例如,在 Visual Studio Code 中開啟這兩個檔案,然後右鍵選擇「選定以進行比較」和「與所選項比較」)
如果您遵循上述方法,檔案之間 project.assets.json
應該只有 1 個差異:
"projectStyle": "PackageReference",
+ "restoreUseLegacyDependencyResolver": true,
"fallbackFolders": [
如果有更多差異,請在 GitHub 上提交包含所有詳細信息的問題。
AssetTargetFallback
屬性 AssetTargetFallback
可讓您指定專案所參考的其他相容架構版本,以及專案使用的 NuGet 套件。
如果您使用 PackageReference
指定套件相依性,但該套件不包含與您的專案目標框架相容的資產,則屬性 AssetTargetFallback
就會生效。 參考套件的相容性會使用 AssetTargetFallback
中指定的每個目標 Framework 來再次檢查。
project
透過參考AssetTargetFallback
或 package
時,將會引發 NU1701 警告。
有關 AssetTargetFallback
如何影響相容性的範例,請參閱下表。
項目架構 | AssetTargetFallback | 套件架構 | 結果 |
---|---|---|---|
.NET Framework 4.7.2 | .NET Standard 2.0 | .NET Standard 2.0 | |
.NET Core 應用程式 3.1 | .NET Standard 2.0、.NET Framework 4.7.2 | .NET Standard 2.0 | |
.NET Core 應用程式 3.1 | .NET Framework 4.7.2 | 不相容,NU1202 發生錯誤。 |
|
.NET Core 應用程式 3.1 | net472;net471 | .NET Framework 4.7.2 | .NET Framework 4.7.2 搭配 NU1701 |
可以指定多個架構,使用;
作為分隔符。 若要新增後援架構,您可以執行下列動作:
<AssetTargetFallback Condition=" '$(TargetFramework)'=='netcoreapp3.1' ">
$(AssetTargetFallback);net472;net471
</AssetTargetFallback>
如果您想要覆寫,可以省略 $(AssetTargetFallback)
,而不是新增至現有的 AssetTargetFallback
值。
注意
如果您使用以 .NET SDK 為基礎的專案,則適當的值已被設定,您無需手動設置。
$(PackageTargetFallback)
是先前嘗試解決這項挑戰的功能,但它基本上已經損壞,不應使用。 若要從 $(PackageTargetFallback)
移轉至 $(AssetTargetFallback)
,只要變更屬性名稱即可。
PrunePackageReference
.NET 運行時間會隨著效能改善和每個版本的新 API 而不斷演進。
執行期間內有許多可用的功能,但這些功能也可以作為套件提供,例如 System.Text.Json。 這通常會導致專案以System.Text.Json 8.0.0
或.NET 9
或.NET 8
為目標。 不需要此相依性,而且建置衝突解決不會使用來自套件的元件,因為它已在 .NET 運行時間中提供。
從 NuGet 6.13 版和 .NET SDK 9.0.200 開始, PrunePackageReference
針對以 .NET SDK 為基礎的專案,在還原時刪除這些套件。
套件剪除是 .NET 9 SDK 的選擇性功能,從 .NET 10 SDK 開始,會預設在所有 .NET
框架和 >= .NET Standard 2.0
中啟用。
套件剪除僅適用於 6.12 中發行的預設相依性解析程式。
PrunePackageReference 規格
要剪除的套件清單是使用 PrunePackageReference
項目來定義。
屬性 | 描述 |
---|---|
版本 | 指定要刪除的最大版本。
1.0.0 表示會剪除最多且包含 1.0.0 的所有套件。 若為 1.0.0 ,則 0.9.0 和 1.0.0 會被剪除,但是 1.0.1 不會。 |
下列屬性可用來修改剪除行為。
屬性名稱 | 描述 |
---|---|
RestoreEnablePackagePruning(還原啟用套件修剪) | 啟用對使用 PrunePackageReference 指定之套件的套件精簡功能。 此屬性是針對每個目標框架設置的,有效值為 true 和 false 。 預設值可能會根據上述定義的 .NET SDK 而有所不同。 |
.NET SDK 會為您預先定義要剪除的套件清單。
PrunePackageReference 的運作方式
當在還原期間指定要截除的套件時,它會從相依性圖表中移除。 此套件不會下載,而且不會出現在任何 NuGet 輸出中。 當封裝被剪除時,會有詳細訊息指出封裝已為指定的目標架構移除。
剪除只支援可轉移的套件,這表示其他套件或項目參考的套件。 下表說明各種封裝剪除行為。
相依性處置 | 行為 |
---|---|
比對透過另一個套件傳遞的可轉移套件標識碼 | 修剪 |
符合通過另一個專案傳遞的遞歸套件的識別碼 | 修剪 |
符合直接的標識碼 PackageReference |
顯示 NU1510 警告,不要移除 |
符合的標識碼 ProjectReference |
引發 NU1511 警告,且不要剪除 |
PrunePackageReference 應用程式
套件修剪的好處有兩方面:
- 效能上的好處,透過減少依賴關係圖中的套件數量
- 透過元件掃描器,例如
NuGetAudit
,減少誤判
使用的 稽核 套件 NuGetAuditMode
設定為 all
時,剪除特別有價值。 如果您使用 .NET 9,建議您將 設定 RestoreEnablePackagePruning
為 true
來嘗試剪除。