PackageReference 在專案檔案中

使用 <PackageReference> MSBuild 專案的套件參考,直接在專案檔內指定 NuGet 套件相依性,而不是有個別 packages.config 的檔案。 使用 PackageReference 不會影響 NuGet 的其他層面。例如,NuGet.Config 檔案中的設定(包括套件來源)仍會套用,如 常見的 NuGet 組態 中所述。

使用 PackageReference,您也可以使用 MSBuild 條件來選擇每個目標架構的套件參考或其他群組。 它也允許對相依性和內容流動進行細微控制。 (如需詳細資訊,請參閱 NuGet 封裝並還原為 MSBuild 目標。

專案類型支援

預設情況下,PackageReference 用於 .NET 專案、.NET Standard 專案,以及以 Windows 10 組建 15063(創意者更新)及更高版本為目標的 UWP 專案,但不包括 C++ UWP 專案。 .NET Framework 專案支援 PackageReference,但目前預設為 packages.config。 若要在 .NET Framework 專案中使用 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>

以下的中繼資料標籤管理相依性資產:

Tag Description 預設值
IncludeAssets 這些資產將被消耗 all
ExcludeAssets 這些資產不會被消耗 none
PrivateAssets 這些資產將被使用,但不會流向父專案 contentfiles;analyzers;build

這些標籤的允許值如下,多個值以分號 all 分隔,但 和 none除外,它們必須單獨出現:

Value Description
編譯 lib 資料夾的內容,以及專案是否能對該資料夾內的組件進行編譯的控制項
執行階段 lib 和 runtimes 資料夾的內容,以及控制是否將這些組件複製到構建輸出目錄的設定。
contentFiles contentfiles 資料夾的內容
組建 .props 和 .targets 在 build 資料夾中
buildMultitargeting (4.0).props 和 .targets 文件,位於 buildMultitargeting 資料夾中,用於跨架構目標的設定
buildTransitive (5.0+).props 和 buildTransitive 在 .targets 資料夾中,適用於可轉移至任何取用專案的資產。 請參閱功能頁面。
analyzers .NET 分析器
原生 native 資料夾的內容
none 以上皆不使用。
all 以上全部 (除了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。

Note

當在 file 中將 developmentDependency 設定為 true 時,即可將套件標示為僅限開發的相依性,以防止該套件被包含為其他套件的相依性。 使用 PackageReference (NuGet 4.8+) 時,此旗標也表示它在編譯時會排除編譯時間資產。 如需詳細資訊,請參閱 PackageReference 的開發相依性支援。

以多個應用框架為目標

SDK 風格專案支援多重目標,透過在 TargetFrameworks 屬性中列出多個值來實現。 當專案針對多個框架時,NuGet restore 會為每個框架產生獨立的相依關係圖,並為 dotnet pack 每個目標建立包含特定框架資產的套件。

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFrameworks>net10.0;netstandard2.0</TargetFrameworks>
  </PropertyGroup>
</Project>

關於如何設定多目標專案的逐步指南,請參閱 「支援專案檔案中的多個 .NET 框架」。

TargetFramework 值的運作方式

TargetFramework專案檔案中的屬性是一個友善名稱,也就是一個別名,會被轉換成規範框架識別。 .NET SDK 透過設定 TargetFrameworkMoniker (TFM),以及在適用時設定 TargetPlatformMoniker 屬性來執行此轉換。

NuGet 使用這些名稱屬性——而非 TargetFramework 字串——來進行套件相容性檢查。 這表示只要名稱屬性設定正確,值 TargetFramework 本身可以是任何字串。

欲了解更多別名機制的細節,請參見 TargetFramework 值是別名。

新增 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以 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>

GeneratePathProperty

這項功能適用於 NuGet 5.0 或更新版本,以及 Visual Studio 2019 16.0 或更新版本。

有時候,可能需要從 MSBuild 目標參考位於套件中的檔案。 在 packages.config 為基礎的專案中,套件會安裝在相對於專案檔的資料夾中。 不過,在 PackageReference 中,套件會從 global-packages 資料夾中使用,該資料夾的位置可能因電腦而異。

為了彌補此差距,NuGet 引入了一個屬性,該屬性指向套件將被使用的位置。

Example:

  <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 檔案。

IsImplicitlyDefined 元資料

有些 SDK 會自動新增 PackageReference 項目。 如果您編寫的 SDK 定義了 PackageReference,請在該項目上設定 IsImplicitlyDefined="true"。 這些元資料告訴 NuGet 工具將套件版本視為由 SDK 控制。 Visual Studio 的 NuGet 套件管理器,且dotnet package update不會針對隱式定義的套件提供套件升級。

<ItemGroup>
  <PackageReference Include="PackageName" Version="1.2.3" IsImplicitlyDefined="true" />
</ItemGroup>

當專案使用 中央套件管理(CPM)時,對於隱含定義的套件,<PackageVersion /> 項目不得定義於 Directory.Packages.props 中,而必須來自 PackageReference 項目本身。 如果 CPM 為相同套件包含 PackageVersion,NuGet 會引發 NU1009 錯誤。

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,隱藏整個專案或全封裝的特定警告。

Examples:

<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 專案上新增 a 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 會解析為 4.1.0 (最接近的最低版本) 。

    • 第 2 天:版本 4.0.0 發行。 NuGet 現在會找到完全相符的版本,並開始解析為 4.0.0。

  • 給定套件版本會從存放庫移除。 雖然 nuget.org 不允許刪除套件,但並非所有套件存放庫都有此條件約束。 這會導致 NuGet 在無法解析為已刪除的版本時尋找最佳相符項目。

Note

對於某些專案類型,.NET SDK 會加入隱含PackageReference項目,使用不同版本的 SDK 會改變套件版本,導致鎖定模式還原失敗。 為了減輕這個問題,你可以使用 global.json 檔案,並將 global.json rollForward 政策 設定為停用。 這表示所有在這個倉庫和你的 CI 管線中工作的開發者,都需要始終使用相同版本的 SDK,但你可以控制隱含套件何時更改版本。

啟用鎖定檔案

若要保持套件相依性的完整狀態,您可以透過設定專案的 MSBuild 屬性 RestorePackagesWithLockFile 來選擇啟用鎖定檔案功能。

<PropertyGroup>
    <!--- ... -->
    <RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
    <!--- ... -->
</PropertyGroup>    

如果設定此屬性,NuGet 還原會在專案根目錄產生鎖定檔案 (packages.lock.json) ,其中列出所有套件相依性。

格式 packages.lock.json 是有版本的。 格式版本取決於你所使用的功能,例如中央套件管理的傳遞釘選或重複有效目標框架。

Note

一旦專案的根目錄中有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,還原操作將會復原鎖定檔案中列出的精確套件;如果您在鎖定檔案建立後更新了專案的已定義套件相依性,還原操作將失敗。

鎖定檔案和 PrunePackageReference

PrunePackageReference 會移除不必要的可轉移套件,以變更專案的相依性。 雖然移除這些套件應該不會在執行階段產生影響,但會影響鎖定檔案。 如果您為現有專案啟用修剪,那麼每當重新生成鎖定檔案時,可能會導致套件數量少於修剪之前。 啟用鎖定模式的鎖定檔案更新檢查具備修剪識別功能,這表示如果您在項目中啟用了修剪功能,該檢查會針對已修剪的套件進行考量。 不過,下次重新產生鎖定檔案時,它會排除修剪的套件,因此您可能會看到比平常更大的差異。

讓鎖定檔案成為您來源存放庫的一部分

如果您要建置應用程式、可執行檔,且有問題的專案位於相依性鏈結的開頭,請將鎖定檔案簽入原始程式碼存放庫,讓 NuGet 可以在還原期間使用它。

不過,如果您的專案是您未發行的程式庫專案,或其他專案所依賴的通用程式碼專案,則 不應 將鎖定檔案簽入為原始程式碼的一部分。 保留鎖定檔案並沒有什麼壞處,但在還原/建置相依於此通用程式碼專案的專案期間,無法使用鎖定檔案中列出的通用程式碼專案的鎖定套件相依性。

Example:

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 同等選項 Description
-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..lock.json。

NuGet 相依性解析程式

NuGet 相依性解析程式會遵循 相依性解析檔中所述的四個規則。

為了改善還原作業的效能和延展性,還原演算法會在 6.12 版本中重寫。 自 6.12 版起,預設會為所有 PackageReference 項目啟用新的還原演算法。 雖然新的還原演算法在功能上相當於先前的演算法,但與任何軟體一樣,Bug 是可能的。 若要還原為先前的實作,請將 MSBuild 屬性 RestoreUseLegacyDependencyResolver 設定為 true。

如果您在 6.12 版本、.NET 9 版本或 17.12 版本中遇到無法在舊版中重現的還原失敗,請在 GitHub 上提出問題。 舊演算法與新演算法之間的任何差異可能會有不同的影響,例如在編譯期間或運行時間。 還有可能變更不會導致失敗,而是還原不同的套件版本。 如果您認為可能會受到任何變更的影響,您可以採取下列步驟來確認 NuGet 還原演算法中的變更是否是根本原因。

復原將其結果寫入 MSBuildProjectExtensionsPath 目錄,可以與新舊演算法進行比較以找出差異。 這通常是 obj 你建置的資料夾。 您可以使用 msbuild.exe 或 dotnet.exe 進行後續步驟。

  1. 移除項目的 obj 資料夾。

  2. 執行 msbuild -t:restore

  3. 將 obj 的內容儲存到標示為 new 行為的位置。

  4. 執行 msbuild -t:restore -p:RestoreUseLegacyDependencyResolver="true"。

  5. 將 obj 的內容儲存到標示為 new 行為的位置。

  6. 比較兩個目錄中的檔案,特別是 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 套件架構 Result
.NET 框架 4.7.2 .NET 標準 2.0 .NET 標準 2.0
.NET Core 應用程式 3.1 .NET Standard 2.0、.NET Framework 4.7.2 .NET 標準 2.0
.NET Core 應用程式 3.1 .NET 框架 4.7.2 不相容,NU1202 發生錯誤。
.NET Core 應用程式 3.1 net472;net471 .NET 框架 4.7.2 .NET Framework 4.7.2 搭配 NU1701

可以指定多個架構,使用;作為分隔符。 若要新增後援架構,您可以執行下列動作:

<AssetTargetFallback Condition=" '$(TargetFramework)'=='netcoreapp3.1' ">
    $(AssetTargetFallback);net472;net471
</AssetTargetFallback>

如果您想要覆寫,可以省略 $(AssetTargetFallback),而不是新增至現有的 AssetTargetFallback 值。

Note

如果您使用以 .NET SDK 為基礎的專案,則適當的值已被設定,您無需手動設置。

$(PackageTargetFallback)是先前嘗試解決這項挑戰的功能,但它基本上已經損壞,不應使用。 若要從 $(PackageTargetFallback) 移轉至 $(AssetTargetFallback),只要變更屬性名稱即可。

使用重複框架進行多重目標設定

此功能需要 NuGet 7.6 / .NET SDK 10.0.300 或更新版本。

由於 TargetFramework 值是別名,多個別名可以解析成 相同的 有效框架。 從 NuGet 7.6 / .NET SDK 10.0.300 開始,NuGet 和 .NET SDK 都支援這種情境。

這使得以下應用場景得以實現:

  • 多RID建置:從單一專案建立平台專屬組件。

    <Project Sdk="Microsoft.NET.Sdk">
      <PropertyGroup>
        <TargetFrameworks>net10.0;linux;ios</TargetFrameworks>
      </PropertyGroup>
    
      <PropertyGroup Condition="'$(TargetFramework)' == 'linux' OR '$(TargetFramework)' == 'ios' OR '$(TargetFramework)' == 'net10.0'">
        <TargetFrameworkIdentifier>.NETCoreApp</TargetFrameworkIdentifier>
        <TargetFrameworkVersion>v10.0</TargetFrameworkVersion>
        <TargetFrameworkMoniker>.NETCoreApp,Version=v10.0</TargetFrameworkMoniker>
      </PropertyGroup>
    </Project>
    
  • 比較不同版本套件的基準測試

    <Project Sdk="Microsoft.NET.Sdk">
      <PropertyGroup>
        <TargetFrameworks>benchmark7.0;benchmark8.0</TargetFrameworks>
      </PropertyGroup>
    
      <!-- Frameworks omitted for brevity-->
    
      <ItemGroup>
        <PackageReference Include="BenchmarkDotNet" Version="0.13.9" />
        <PackageReference Include="Contoso.FastLibrary" Version="7.0" Condition="'$(TargetFramework)' == 'benchmark7.0' "/>
        <PackageReference Include="Contoso.FastLibrary" Version="8.0" Condition="'$(TargetFramework)' == 'benchmark8.0' "/>
      </ItemGroup>
    </Project>
    

套件

NuGet 套件每個有效框架只能包含一組建置輸出和一個相依群組。 當你打包一個含有重複有效框架的專案時,你必須告訴 NuGet 哪個別名貢獻了這些資產,否則該包將產生 NU5051。 有關解決步驟與範例,請參見 NU5051 。

專案參考

當一個專案參考另一個包含多個別名且解析為同一框架的專案時,NuGet 會使用別名作為決定因素。 如果參考專案的別名與該專案名稱相同,則優先使用該別名。 如果沒有匹配的名稱且存在多個候選,NuGet 會回報錯誤。

局限性

  • 只有 SDK 風格的專案才支援重複且有效的框架。
  • 含有路徑分隔字元(/ 或 \)的別名會被阻擋。
  • Visual Studio 的套件管理器介面沒有特別支援重複框架,但你可以直接編輯專案檔案或使用 dotnet CLI 來管理套件。

PrunePackageReference

.NET 運行時間會隨著效能改善和每個版本的新 API 而不斷演進。 新增至 .NET 的新功能有時也會以套件的形式提供,讓使用舊版目標架構的開發人員可以使用程式庫,例如 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 SDK 10 開始,套件修剪也影響直接套件。

套件修剪作為 .NET 9 SDK 的自選功能提供,而在以 .NET 10 SDK 為目標的專案中,預設會對所有框架啟用此功能 >= .NET 10.0。

套件剪除僅適用於 6.12 中發行的預設相依性解析程式。

PrunePackageReference 規格

要剪除的套件清單是使用 PrunePackageReference 項目來定義。

Attributes Description
Version 指定要刪除的最大版本。 1.0.0 表示會剪除最多且包含 1.0.0 的所有套件。 若為 1.0.0,則 0.9.0 和 1.0.0 會被剪除,但是 1.0.1 不會。

下列屬性可用來修改剪除行為。

PropertyName Description
RestoreEnablePackagePruning 啟用對使用 PrunePackageReference 指定之套件的套件精簡功能。 此屬性是針對每個目標框架設置的,有效值為 true 和 false。 預設值可能會根據上述定義的 .NET SDK 而有所不同。

.NET SDK 會為您預先定義要剪除的套件清單。 這個清單是根據你專案中指定的共用框架來決定的。 只考慮直接框架參考,且透過 套件導入的框架不會加入修剪資料。

PrunePackageReference 的運作方式

當在還原期間指定要截除的套件時,它會從相依性圖表中移除。 當套件被移除時,一則訊息會在詳細程度的模式中顯示,指示已為指定的目標架構移除套件。

對於可轉移的套件,這表示其他套件或專案的相依性,套件不會下載,也不會出現在 NuGet 的任何輸出中。

對於直接套件, PrivateAssets='all' 和 IncludeAssets='none' 會隱含套用。

  • IncludeAssets='none' 確保此套件中的元件不會在建置期間使用。 在修剪出現之前,建置期間的衝突解決機制確保平臺元件會優先於來自套件的元件。
  • PrivateAssets='all' 可確保套件不直接或透過專案參考包含於其他套件中。

Example:

如下所示的專案:

  <PropertyGroup>
    <TargetFrameworks>net9.0;netstandard2.0</TargetFrameworks>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="System.Text.Json" Version="9.0.4" />
  </ItemGroup>

會具有以下相依性條件的 nuspec:

<dependencies>
    <group targetFramework=".NETFramework4.7.2">
        <dependency id="System.Text.Json" version="9.0.4" />
    </group>
    <group targetFramework="net9.0">
    </group>
</dependencies>

當可以直接從您的專案中移除 PackageReference,且其中一個項目架構為 .NET 10 或更新版本時,將會引發 NU1510 ,要求您移除套件。 遵循此建議可減少項目圖形的複雜度。

下表總結介紹所有套件修剪行為。

相依性處置 Behavior
比對透過另一個套件傳遞的可轉移套件標識碼 Prune
符合通過另一個專案傳遞的遞歸套件的識別碼 Prune
符合直接的標識碼 PackageReference 套用 PrivateAssets='all' 和 IncludeAssets='none',並引發 NU1510 警告,當套件可從所有框架移除,且專案針對 .NET 10 時。
符合的標識碼 ProjectReference 當專案以 .NET 10 為目標時,請勿執行修剪操作以避免引發 NU1511 警告

PrunePackageReference 應用程式

套件修剪的好處有兩方面:

  • 效能上的好處,透過減少依賴關係圖中的套件數量
  • 透過元件掃描器,例如 NuGetAudit,減少誤判

將稽核設為 NuGetAuditMode的套件all時,精簡特別有價值。 如果您使用 .NET 9,建議您將設定 RestoreEnablePackagePruning 為 true來嘗試修剪。