.NET 專案 SDK
現代 .NET 專案與專案軟體開發套件 (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.Razor |
.NET Razor SDK | https://github.com/dotnet/aspnetcore |
Microsoft.NET.Sdk.BlazorWebAssembly |
.NET Blazor WebAssembly SDK | https://github.com/dotnet/aspnetcore |
Microsoft.NET.Sdk.Worker |
The .NET 背景工作服務 SDK | https://github.com/dotnet/aspnetcore |
Aspire.AppHost.Sdk |
.NET Aspire SDK | https://github.com/dotnet/aspire |
MSTest.Sdk |
MSTest SDK | https://github.com/microsoft/testfx |
.NET SDK 是 .NET 的基礎 SDK。 其他 SDK 都會參考 .NET SDK,而與其他 SDK 相關聯的專案則會具備所有可用的 .NET SDK 屬性。 例如,Web SDK 相依於 .NET SDK 和 Razor SDK 兩者。
對於 Forms 和 Windows Presentation Foundation (WPF) 專案,您可以指定 .NET SDK (Microsoft.NET.Sdk
) 並在專案檔中設定一些其他屬性。 如需詳細資訊,請參閱啟用 .NET Desktop SDK。
MSBuild SDK 可供您用來設定和擴充組建,會列在 MSBuild SDK 中。
您也可以製作可透過 NuGet 散發的自有 SDK。
專案檔
.NET 專案採用 MSBuild 格式。 專案檔的格式會是 XML,其中 C# 專案的副檔名為 .csproj,而 F# 專案的副檔名則為 .fsproj。 MSBuild 專案檔的根項目為 Project 元素。 Project
元素的選用屬性 Sdk
可指定要使用的 SDK (和版本)。 若要使用 .NET 工具並建置程式碼,請將 Sdk
屬性設定為可用 SDK 資料表中的任一識別碼。
<Project Sdk="Microsoft.NET.Sdk">
<!-- Omitted for brevity... -->
</Project>
Project/Sdk
屬性和Sdk
元素會啟用加總 SDK。 請考慮下列範例,其中 .NET Aspire SDK (Aspire.AppHost.Sdk
) 會新增至 專案頂端 Microsoft.NET.Sdk
:
<Project Sdk="Microsoft.NET.Sdk">
<Sdk Name="Aspire.AppHost.Sdk" Version="9.0.0" />
<!-- Omitted for brevity... -->
</Project>
在上述項目檔中,這兩個 SDK 都用來解析加法本質中的相依性。 如需詳細資訊,請參閱 .NET Aspire SDK
指定來自 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.props 和 Sdk.targets 檔案。
前置處理專案檔
使用 dotnet msbuild -preprocess
包含 SDK 和其目標後,您就可以看到完全展開的專案,與 MSBuild 看到的內容相同。 dotnet msbuild
命令的前置處理參數可顯示匯入的檔案、檔案來源以及檔案對組建的貢獻,而不會實際建置專案。
若專案有多個目標 Framework,請將一個架構指定為 MSBuild 屬性,藉此讓命令結果只專注於一個架構。 例如:
dotnet msbuild -property:TargetFramework=net8.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 Desktop SDK 有其他適用於 WPF 的包含項目及排除項目。 如需詳細資訊,請參閱 WPF 預設包含及排除。
如果您在專案檔中明確定義任何這些項目,您可能會收到 NETSDK1022 建置錯誤。 如需如何解決錯誤的資訊,請參閱 NETSDK1022:包含重複的項目。
隱含 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 8 SDK 開始, System.Net.Http 在以 .NET Framework 為目標時,不再包含 於 中 Microsoft.NET.Sdk
。
隱含套件參考
當您的專案以 .NET Standard 1.0-2.0 為目標時,.NET SDK 會將隱含參考新增至特定的中繼套件。 中繼套件是以架構為基礎的套件,只會包含其他套件的相依性。 中繼套件是根據專案檔的 TargetFramework 或 TargetFrameworks (複數) 屬性中指定的目標架構隱含被參考的。
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net462</TargetFrameworks>
</PropertyGroup>
如有需要,您可以透過 DisableImplicitFrameworkReferences 屬性停用隱含套件參考,也可以將明確參考只新增至所需架構或套件。
建議:
- 以 .NET Framework 或 .NET Standard 1.0-2.0 為目標時,請勿透過專案檔中的
<PackageReference>
項目,將明確參考新增至NETStandard.Library
中繼套件。 對於 .NET Standard 1.0-2.0 專案,會隱含參考這些中繼套件。 在 .NET Framework 專案中,若使用以 .NET Standard 為基礎的 NuGet 套件時需要任何版本的NETStandard.Library
,則 NuGet 會自動安裝該版本。 - 以 .NET Standard 1.0-2.0 為目標時,若您需要特定版本的
NETStandard.Library
中繼套件,可以使用<NetStandardImplicitPackageVersion>
屬性並設定所需版本。
建置事件
在 SDK 型專案中,使用名為 PreBuild
或 PostBuild
的 MSBuild 目標,並針對 PreBuild
設定 BeforeTargets
屬性或針對 PostBuild
設定 AfterTargets
。
<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
<Exec Command=""$(ProjectDir)PreBuildEvent.bat" "$(ProjectDir)..\" "$(ProjectDir)" "$(TargetDir)"" />
</Target>
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
<Exec Command="echo Output written to $(TargetDir)" />
</Target>
注意
- 您可以對 MSBuild 目標使用任何名稱。 不過 Visual Studio 整合式開發環境 (IDE) 會辨識出
PreBuild
和PostBuild
目標,因此您可以使用這些名稱在 IDE 中編輯命令。 - SDK 型專案中不建議使用屬性
PreBuildEvent
和PostBuildEvent
,因為$(ProjectDir)
等巨集不會受到解析。 例如,下列程式碼並不受支援:
<PropertyGroup>
<PreBuildEvent>"$(ProjectDir)PreBuildEvent.bat" "$(ProjectDir)..\" "$(ProjectDir)" "$(TargetDir)"</PreBuildEvent>
</PropertyGroup>
自訂組建
自訂組建有許多種方式。 您可能希望透過將屬性作為引數傳遞給 msbuild 或 dotnet 命令來覆寫該屬性。 您也可以將屬性新增至專案檔或 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 範例儲存機制,查看此類協同作用範例。