PackageReference
在項目檔中
使用 <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>
下列中繼資料標記控制相依性資產:
標記 | 描述 | 預設值 |
---|---|---|
IncludeAssets | 會取用這些資產 | 全部 |
ExcludeAssets | 不會取用這些資產 | none |
PrivateAssets | 會取用這些資產,但不會流動至父專案 | contentfiles;分析器;建置 |
這些標記的可允許值如下,使用分號隔開多個值,但 all
和 none
必須單獨出現:
值 | Description |
---|---|
compile | lib 資料夾的內容,以及專案是否能對該資料夾內的組件進行編譯的控制項 |
執行階段 | lib 與 runtimes 資料夾的內容,以及是否能將這些組件複製到組建輸出目錄的控制項 |
contentFiles | contentfiles 資料夾的內容 |
build | build 資料夾中的 .props 與 .targets |
buildMultitargeting | (4.0) .props 和 .targets buildMultitargeting 資料夾中的跨架構目標 |
buildTransitive | (5.0+).props buildTransitive 在 .targets 資料夾中,針對可轉移至任何取用項目的資產。 請參閱功能頁面 \(英文\)。 |
analyzers | .NET 分析器 |
native | 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
,所以目標與 props「會」流動至父專案。 例如,考慮到上述參考會用在建置名為 AppLogger 之 NuGet 套件的專案中。 AppLogger 可從 Contoso.Utility.UsefulStuff
取用目標與 props,如同專案可以取用 AppLogger。
注意
在 .nuspec
檔案中,當 developmentDependency
設定為 true
時可讓套件成為僅限開發相依性,這可防止套件被包含為其他套件的相依性。 使用 PackageReference (NuGet 4.8+) 時,此旗標也表示它在編譯時會排除編譯時間資產。 如需詳細資訊,請參閱 PackageReference 的 DevelopmentDependency 支援 \(英文\)。
新增 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
目標:
條件也可以套用在 ItemGroup
層級,並且套用至所有子系 PackageReference
項目:
<ItemGroup Condition = "'$(TargetFramework)' == 'net452'">
<!-- ... -->
<PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
<PackageReference Include="Contoso.Utility.UsefulStuff" Version="3.6.0" />
<!-- ... -->
</ItemGroup>
GeneratePathProperty
這項功能適用於 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 開始,相當於 ProjectReference,PackageReference 支援 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 天:若您指定
<PackageReference Include="My.Sample.Lib" Version="4.0.0"/>
,但 NuGet 存放庫上可用的版本是 4.1.0、4.2.0 與 4.3.0。 在此案例中,NuGet would 將會解析為 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
,其鎖定檔案將會包含版本2.0.0
相PackageX
依性,而不會1.0.0
如的鎖定檔案ProjectB
所列。 因此,一般程式碼專案的鎖定檔案對於相依於它之專案的解析套件沒有多大決定權。
鎖定檔案擴充性
您使用鎖定檔案來控制還原的各種行為,如下所述:
NuGet.exe選項 | dotnet 選項 | MSBuild 同等選項 | 描述 |
---|---|---|---|
-UseLockFile |
--use-lock-file |
RestorePackagesWithLockFile | 選擇使用鎖定檔案。 |
-LockedMode |
--locked-mode |
RestoreLockedMode | 針對還原啟用鎖定模式。 這在您想要可重複建置的 CI/CD 案例中很有用。 |
-ForceEvaluate |
--force-evaluate |
RestoreForceEvaluate | 對於專案中已定義浮動版本的套件而言,此選項非常實用。 根據預設,除非您使用此選項執行還原,否則 NuGet 還原不會在每個還原時自動更新套件版本。 |
-LockFilePath |
--lock-file-path |
NuGetLockFilePath | 為專案定義自訂鎖定檔案位置。 根據預設,NuGet 支援根目錄的 packages.lock.json 。 若您在相同的目錄中有多個專案,NuGet 支援專案特定鎖定檔案 packages.<project_name>.lock.json |
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 為基礎的專案,則會設定適當的 $(AssetTargetFallback)
值,而且您不需要手動設定它們。
$(PackageTargetFallback)
是先前嘗試解決這項挑戰的功能,但它基本上已中斷,不應使用。 若要從 $(PackageTargetFallback)
移轉至 $(AssetTargetFallback)
,只要變更屬性名稱即可。