現代 .NET 專案與專案軟體開發套件 (SDK) 相關聯。 每個「專案 SDK」都是 MSBuild 目標,和相關工作的組合,而這些工作會負責編譯、封裝和發佈程式碼。 參考專案 SDK 的專案有時也稱為「SDK 型專案」。
可用的 SDK
可用的 SDK 包括:
| ID | 描述 | 存放庫 |
|---|---|---|
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 Worker Service 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 可供您用來設定和擴充組建,相關 SDK 列在 MSBuild SDKs。
您也可以製作可透過 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。 請考慮下列範例,其中 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 都用來解析加法本質中的相依性。 如需詳細資訊,請參閱 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.props 的隱含匯入,並在最下方新增 Sdk.targets 的隱含匯入。
<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
預設設定中的包含及排除項目
SDK 會自動管理三種專案項目:
-
Compile項目:原始碼檔案(*.cs、*.vb及其他語言特定的副檔名),這些檔案會被編譯成你的組件。 -
EmbeddedResource項目:*.resx嵌入到程序集中的檔案。 -
None項目:專案中追蹤的所有其他檔案,如設定檔和內容檔,但未被編譯或嵌入。
與非 SDK .NET Framework 專案不同的是,您無需在專案檔中指定這些項目,因為預設值即可涵蓋常見的大多數使用案例。 此行為可讓專案檔變小,也更容易理解並手動編輯 (如有需要)。
SDK 使用 顆粒 模式來判定各項目類型的檔案:
- 包含 glob:指定要加入哪些檔案到該項目類型。
- 排除 glob:指定套用包含 glob 時要跳過哪些檔案。
- 移除 glob:指定從已由包含 glob 新增的項目中移除哪些檔案。
下表顯示 .NET SDK 中每種項目類型的預設 glob 模式:
| 元素 | 包含 Glob | 排除 Glob | 移除 Glob |
|---|---|---|---|
| Compile | **/*.cs (或其他語言副檔名) | **/*.user; **/*.*proj; **/*.sln(x); **/*.vssscc | N/A |
| EmbeddedResource | **/*.resx (資源檔案格式) | **/*.user; **/*.*proj; **/*.sln(x); **/*.vssscc | N/A |
| None | **/* | **/*.user; **/*.*proj; **/*.sln(x); **/*.vssscc | **/*.cs;**/*.resx |
因為None使用**/*作為其包含 glob,否則會包含已被Compile和EmbeddedResource捕捉的.cs和.resx檔案。 移除 glob**/*.cs; **/*.resx() 可防止這些檔案同時出現在兩種項目類型中。
注意
分別由 MSBuild 屬性./bin 和./obj表示的$(BaseOutputPath) 和$(BaseIntermediateOutputPath) 資料夾會預設從 glob 模式中排除。
DefaultItemExcludes 屬性用來表示排除項目。
.NET Desktop SDK 有其他適用於 WPF 的包含項目及排除項目。 如需詳細資訊,請參閱 WPF 預設包含及排除。
警告
避免定義重複 SDK 預設 Include glob 的 Compile、EmbeddedResource 或 None 項目。 重複包含的檔案會導致建置中包含相同的檔案兩次,導致建置 NETSDK1022 錯誤。 支援使用 Remove 或 Update 的自訂功能,或是在你設定 EnableDefaultItems、 EnableDefaultCompileItems 或 EnableDefaultEmbeddedResourceItems 為 false 之後新增物品。 如需如何解決錯誤的資訊,請參閱 NETSDK1022:包含重複的項目。
隱含使用指令
自 .NET 6 起,新的 C# 專案會加入隱含 global using 指示詞。 這代表您可以使用這些命名空間中所定義的類型,而無須指定完整名稱或手動新增 using 指示詞。 「隱含的」層面指的是,在專案的 obj 目錄中生成的檔案會新增 global using 指令。
會加入隱性 global using 指令給使用下列任一 SDK 的專案:
Microsoft.NET.SdkMicrosoft.NET.Sdk.WebMicrosoft.NET.Sdk.WorkerMicrosoft.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 開始,
隱含套件參考
當您的專案以 .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 目標,並針對 BeforeTargets 設定 PreBuild 屬性或針對 AfterTargets 設定 PostBuild。
<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 samples 儲存庫查看此類協同作用範例。