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;分析器;建置

這些標記的可允許值如下,使用分號隔開多個值,但 allnone 必須單獨出現:

Description
compile lib 資料夾的內容,以及專案是否能對該資料夾內的組件進行編譯的控制項
執行階段 libruntimes 資料夾的內容,以及是否能將這些組件複製到組建輸出目錄的控制項
contentFiles contentfiles 資料夾的內容
build build 資料夾中的 .props.targets
buildMultitargeting 用於跨架構目標的 (4.0).propsbuildMultitargeting 資料夾中的 .targets
buildTransitive (5.0+)buildTransitive 資料夾中的 .props.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 目標:

The result of applying a Condition on PackageReference with VS2017

條件也可以套用在 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.0ProjectB,則 ProjectB 的鎖定檔案將會列出對 PackageX 版本 1.0.0 的相依性。 不過,當建置 ProjectA 時,其鎖定檔案將會包含對 PackageX 版本 2.0.0 的相依性,而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

AssetTargetFallback

屬性 AssetTargetFallback 可讓您為項目參考的專案指定其他相容的架構版本,以及專案所取用的 NuGet 套件。

如果您使用 指定套件相依性 PackageReference ,但該套件不包含與專案目標架構相容的資產,屬性 AssetTargetFallback 就會生效。 參考套件的相容性會使用 AssetTargetFallback 中指定的每個目標 Framework 來重新檢查。 project透過參考AssetTargetFallbackpackage 時,將會引發 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),只要變更屬性名稱即可。