.NET 專案 SDK

.NET Core 和 .NET 5 以上版本的專案會與軟體開發套件 (SDK) 相關聯。 每個「專案 SDK」都是 MSBuild 目標,和相關工作的組合,而這些工作會負責編譯、封裝和發佈程式碼。 參考專案 SDK 的專案有時也稱為「SDK 型專案」

可用的 SDK

下列為可用的 SDK:

識別碼 描述 存放庫
Microsoft.NET.Sdk .NET SDK https://github.com/dotnet/sdk
Microsoft.NET.Sdk.Web .NET Web SDK https://github.com/dotnet/sdk
Microsoft.NET.Sdk.BlazorWebAssembly .NET Blazor WebAssembly SDK https://github.com/dotnet/aspnetcore
Microsoft.NET.Sdk.Razor .NET Razor SDK https://github.com/dotnet/aspnetcore
Microsoft.NET.Sdk.Worker The .NET 背景工作服務 SDK
Microsoft.NET.Sdk.WindowsDesktop .NET 桌面 SDK,其中包含 Windows Forms (WinForms) 和 Windows Presentation Foundation (WPF)。* https://github.com/dotnet/winformshttps://github.com/dotnet/wpf

.NET SDK 是 .NET 的基礎 SDK。 其他 SDK 都會參考 .NET SDK,而與其他 SDK 相關聯的專案則會具備所有可用的 .NET SDK 屬性。 例如,Web SDK 相依於 .NET SDK 和 Razor SDK 兩者。

您也可以製作可透過 NuGet 散發的自有 SDK。

*自 .NET 5 起,Windows Forms 和 Windows Presentation Foundation (WPF) 專案應指定 .NET SDK (Microsoft.NET.Sdk),而非指定 Microsoft.NET.Sdk.WindowsDesktop。 若針對這類專案將 TargetFramework 設定為 net5.0-windows,以及將 UseWPF 或 若UseWindowsForms 設定為 true,即會自動匯入 Windows 桌面 SDK。 若您的專案以 .NET 5 或更新版本為目標,且指定了 Microsoft.NET.Sdk.WindowsDesktop SDK,則您會收到組建警告 NETSDK1137。

專案檔

.NET 專案採用 MSBuild 格式。 專案檔的格式會是 XML,其中 C# 專案的副檔名為 .csproj,而 F# 專案的副檔名則為 .fsproj。 MSBuild 專案檔的根項目為 Project 元素。 Project 元素的選用屬性 Sdk 可指定要使用的 SDK (和版本)。 若要使用 .NET 工具並建置程式碼,請將 Sdk 屬性設定為可用 SDK 資料表中的任一識別碼。

<Project Sdk="Microsoft.NET.Sdk">
  ...
</Project>

指定來自 NuGet 的 SDK,在名稱結尾包含版本,或在 global.json 檔案中指定名稱和版本。

<Project Sdk="MSBuild.Sdk.Extras/2.0.54">
  ...
</Project>

指定 SDK 的另一個方式是使用頂層 Sdk 元素:

<Project>
  <Sdk Name="Microsoft.NET.Sdk" />
  ...
</Project>

以下列任一方式參考 SDK 都可大幅簡化 NET 專案檔。 評估專案時,MSBuild 會在專案檔的最上方以及最下方的 Sdk.targets 加入 Sdk.props 的隱含匯入。

<Project>
  <!-- Implicit top import -->
  <Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />
  ...
  <!-- Implicit bottom import -->
  <Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />
</Project>

提示

在 Windows 機器上,您可以在 %ProgramFiles%\dotnet\sdk\[版本]\Sdks\Microsoft.NET.Sdk\Sdk 資料夾中找到 Sdk.propsSdk.targets 檔案。

前置處理專案檔

使用 dotnet msbuild -preprocess 包含 SDK 和其目標後,您就可以看到完全展開的專案,與 MSBuild 看到的內容相同。 dotnet msbuild 命令的前置處理參數可顯示匯入的檔案、檔案來源以及檔案對組建的貢獻,而不會實際建置專案。

若專案有多個目標 Framework,請將一個架構指定為 MSBuild 屬性,藉此讓命令結果只專注於一個架構。 例如:

dotnet msbuild -property:TargetFramework=netcoreapp2.0 -preprocess:output.xml

預設的包含和排除

Compile 項目內嵌資源None 項目 的預設包含及排除會在 SDK 中定義。 與非 SDK .NET Framework 專案不同的是,您無需在專案檔中指定這些項目,因為預設值即可涵蓋常見的大多數使用案例。 此行為可讓專案檔變小,也更容易理解並手動編輯 (如有需要)。

下表會說明 .NET SDK 中的元素以及包含和排除 Glob

Element 包含 Glob 排除 Glob 移除 Glob
Compile **/*.cs (或其他語言副檔名) **/*.user;**/*.*proj;**/*.sln;**/*.vssscc N/A
EmbeddedResource **/*.resx **/*.user;**/*.*proj;**/*.sln;**/*.vssscc N/A
None **/* **/*.user;**/*.*proj;**/*.sln;**/*.vssscc **/*.cs;**/*.resx

注意

分別由 $(BaseOutputPath)$(BaseIntermediateOutputPath) MSBuild 屬性表示的 ./bin./obj 資料夾會預設從 Glob 排除。 DefaultItemExcludes 屬性會表示排除。

.NET 桌面 SDK 有更多適用於 WPF 的包含及排除。 如需詳細資訊,請參閱 WPF 預設包含及排除

建置錯誤

若您在專案檔中明確定義上述任一項目,您可能會收到類似下列的 "NETSDK1022" 建置錯誤:

包含了重複的 'Compile' 項目。 根據預設,.NET SDK 會包含來自您專案目錄的 'Compile' 項目。 您可以從專案檔移除這些項目,或若想要在專案檔中明確地納入這些項目,也可以將 'EnableDefaultCompileItems' 屬性設定為 'false'。

包含了重複的 'EmbeddedResource' 項目。 根據預設,.NET SDK 會包含來自您專案目錄的 'EmbeddedResource' 項目。 您可以從專案檔移除這些項目,或若想要在專案檔中明確地納入這些項目,也可以將 'EnableDefaultEmbeddedResourceItems' 屬性設定為 'false'。

若要解決錯誤,請執行下列任一種方法:

  • 移除與上表所列之隱含項目相符的明確 CompileEmbeddedResourceNone 項目。

  • EnableDefaultItems 屬性設為 false,以停用所有隱含的檔案包含:

    <PropertyGroup>
      <EnableDefaultItems>false</EnableDefaultItems>
    </PropertyGroup>
    

    若您想要將檔案指定為與應用程式一同發佈,仍可以使用已知的 MSBuild 機制來達成該目的,例如 Content 元素。

  • EnableDefaultCompileItemsEnableDefaultEmbeddedResourceItemsEnableDefaultNoneItems 屬性設為 false,以選擇性地只停用 CompileEmbeddedResourceNone Glob:

    <PropertyGroup>
      <EnableDefaultCompileItems>false</EnableDefaultCompileItems>
      <EnableDefaultEmbeddedResourceItems>false</EnableDefaultEmbeddedResourceItems>
      <EnableDefaultNoneItems>false</EnableDefaultNoneItems>
    </PropertyGroup>
    

    若您只停用 Compile Glob,Visual Studio 內的方案總管仍會在專案中顯示 *.cs 項目,並將其包含為 None 項目。 若要停用隱含 None Glob,請也將 EnableDefaultNoneItems 設為 false

隱含 using 指示詞

自 .NET 6 起,新的 C# 專案會加入隱含 global using 指示詞。 這代表您可以使用這些命名空間中所定義的類型,而無須指定完整名稱或手動新增 using 指示詞。 「隱含」層面指的是 global using 指示詞會新增至專案 obj 目錄中產生的檔案。

使用下列任一 SDK 的專案都會加入隱含 global using 指示詞:

  • Microsoft.NET.Sdk
  • Microsoft.NET.Sdk.Web
  • Microsoft.NET.Sdk.Worker
  • Microsoft.NET.Sdk.WindowsDesktop

在採用專案 SDK 的一系列預設命名空間中,每個命名空間都會加入 global using 指示詞。 下表會顯示這些預設的命名空間。

SDK 預設的命名空間
Microsoft.NET.Sdk System
System.Collections.Generic
System.IO
System.Linq
System.Net.Http
System.Threading
System.Threading.Tasks
Microsoft.NET.Sdk.Web Microsoft.NET.Sdk 命名空間
System.Net.Http.Json
Microsoft.AspNetCore.Builder
Microsoft.AspNetCore.Hosting
Microsoft.AspNetCore.Http
Microsoft.AspNetCore.Routing
Microsoft.Extensions.Configuration
Microsoft.Extensions.DependencyInjection
Microsoft.Extensions.Hosting
Microsoft.Extensions.Logging
Microsoft.NET.Sdk.Worker Microsoft.NET.Sdk 命名空間
Microsoft.Extensions.Configuration
Microsoft.Extensions.DependencyInjection
Microsoft.Extensions.Hosting
Microsoft.Extensions.Logging
Microsoft.NET.Sdk.WindowsDesktop (Windows Forms) Microsoft.NET.Sdk 命名空間
System.Drawing
System.Windows.Forms
Microsoft.NET.Sdk.WindowsDesktop (WPF) Microsoft.NET.Sdk 命名空間
已移除 System.IO
已移除 System.Net.Http

若您想要停用此功能,或想要在現有的 C# 專案中啟用隱含 global using 指示詞,您可以透過 ImplicitUsings MSBuild 屬性 來達成。

您可以在專案檔中新增 Using 項目 (或 Visual Basic 專案則為 Import 項目),藉此指定其他隱含 global using 指示詞,例如:

<ItemGroup>
  <Using Include="System.IO.Pipes" />
</ItemGroup>

隱含套件參考

以 .NET Core 1.0 - 2.2 或 .NET Standard 1.0 - 2.0 為目標時,.NET SDK 會將隱含參考新增至特定「中繼套件」。 中繼套件是以架構為基礎的套件,只會包含其他套件的相依性。 中繼套件會受到隱含參考,參考依據為專案檔 TargetFrameworkTargetFrameworks 屬性中所指定的目標架構。

<PropertyGroup>
  <TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup>
<PropertyGroup>
  <TargetFrameworks>netcoreapp2.1;net462</TargetFrameworks>
</PropertyGroup>

如有需要,您可以透過 DisableImplicitFrameworkReferences 屬性停用隱含套件參考,也可以將明確參考只新增至所需架構或套件。

建議:

  • 以 .NET Framework、.NET Core 1.0 - 2.2 或 .NET Standard 1.0 - 2.0 為目標時,請勿透過專案檔中的 <PackageReference> 項目,將明確參考新增至 Microsoft.NETCore.AppNETStandard.Library 中繼套件。 .NET Core 1.0 - 2.2 和 .NET Standard 1.0 - 2.0 專案會隱含參考這些中繼套件。 在 .NET Framework 專案中,若使用以 .NET Standard 為基礎的 NuGet 套件時需要任何版本的 NETStandard.Library,則 NuGet 會自動安裝該版本。
  • 以 .NET Core 1.0 - 2.2 為目標時,若您需要特定版本的執行階段,請使用專案中的 <RuntimeFrameworkVersion> 屬性 (例如 1.0.4),而不要參考中繼套件。 例如,當您使用獨立部署時,可能會需要 1.0.0 LTS 執行階段的特定修補檔版本。
  • 以 .NET Standard 1.0 - 2.0 為目標時,若您需要特定版本的 NETStandard.Library 中繼套件,可以使用 <NetStandardImplicitPackageVersion> 屬性並設定所需版本。

建置事件

在 SDK 型專案中,使用名為 PreBuildPostBuild 的 MSBuild 目標,並針對 PreBuild 設定 BeforeTargets 屬性或針對 PostBuild 設定 AfterTargets

<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
    <Exec Command="&quot;$(ProjectDir)PreBuildEvent.bat&quot; &quot;$(ProjectDir)..\&quot; &quot;$(ProjectDir)&quot; &quot;$(TargetDir)&quot;" />
</Target>

<Target Name="PostBuild" AfterTargets="PostBuildEvent">
   <Exec Command="echo Output written to $(TargetDir)" />
</Target>

注意

  • 您可以對 MSBuild 目標使用任何名稱。 不過 Visual Studio 整合式開發環境 (IDE) 會辨識出 PreBuildPostBuild 目標,因此您可以使用這些名稱在 IDE 中編輯命令。
  • SDK 型專案中不建議使用屬性 PreBuildEventPostBuildEvent,因為 $(ProjectDir) 等巨集不會受到解析。 例如,下列程式碼並不受支援:
<PropertyGroup>
  <PreBuildEvent>"$(ProjectDir)PreBuildEvent.bat" "$(ProjectDir)..\" "$(ProjectDir)" "$(TargetDir)"</PreBuildEvent>
</PropertyGroup>

自訂組建

自訂組建有許多種方式。 您可以將屬性作為引數傳遞至 msbuilddotnet 命令,藉此覆寫該屬性。 您也可以將屬性新增至專案檔或 Directory.Build.props 檔案。 如需 .NET 專案的實用屬性清單,請參閱 .NET SDK 專案的 MSBuild 參考

提示

若要從命令列建立新的 Directory.Build.props 檔案,一個簡單的方式是在存放庫的根使用命令 dotnet new buildprops

自訂目標

.NET 專案可封裝自訂 MSBuild 目標及屬性,以供取用套件的專案使用。 當您想要執行下列作業時,請使用此類型的擴充性:

  • 延伸建置流程。
  • 存取組建流程的成品,例如產生的檔案。
  • 檢查組建叫用所在位置之上的組態。

您可以將檔案以 <package_id>.targets<package_id>.props 形式 (例如 Contoso.Utility.UsefulStuff.targets) 放在專案的 build 資料夾中。

下列 XML 是.csproj 檔案中的程式碼片段,會指示 dotnet pack 命令要封裝的內容。 <ItemGroup Label="dotnet pack instructions"> 元素會將目標檔案放在套件內的 build 資料夾中。 <Target Name="CollectRuntimeOutputs" BeforeTargets="_GetPackageFiles"> 元素會將組件和 .json 檔案放到 build 資料夾中。

<Project Sdk="Microsoft.NET.Sdk">

  ...
  <ItemGroup Label="dotnet pack instructions">
    <Content Include="build\*.targets">
      <Pack>true</Pack>
      <PackagePath>build\</PackagePath>
    </Content>
  </ItemGroup>
  <Target Name="CollectRuntimeOutputs" BeforeTargets="_GetPackageFiles">
    <!-- Collect these items inside a target that runs after build but before packaging. -->
    <ItemGroup>
      <Content Include="$(OutputPath)\*.dll;$(OutputPath)\*.json">
        <Pack>true</Pack>
        <PackagePath>build\</PackagePath>
      </Content>
    </ItemGroup>
  </Target>
  ...

</Project>

若要在專案中取用自訂目標,請新增會指向套件及其版本的 PackageReference 元素。 與工具不同,自訂目標套件會包含在進行取用之專案的相依性範圍中。

您可以設定自訂目標的使用方式。 由於自訂目標為 MSBuild 目標,因此可相依於指定目標、在另一個目標之後執行,或透過 dotnet msbuild -t:<target-name> 命令手動叫用。 不過,您可以結合個別專案工具和自訂目標,以提供更優質的使用者體驗。 在此案例中,個別專案工具會接受所需的任何參數,並會將參數轉譯為將執行目標的必要 dotnet msbuild 叫用。 您可以在 dotnet-packer 專案中的 MVP Summit 2016 Hackathon 範例儲存機制,查看此類協同作用範例。

另請參閱