.NET SDKs für Projekte
Modernen .NET Core-Projekten ist ein Projekt-SDK (Software Development Kit) zugeordnet. Jedes Projekt-SDK besteht aus einer Reihe von MSBuild-Zielen und zugehörigen Tasks, mit denen Code kompiliert, paketiert und veröffentlicht wird. Ein Projekt, das auf ein Projekt-SDK verweist, wird zuweilen auch als Projekt im SDK-Stil bezeichnet.
Verfügbare SDKs
Folgende SDKs sind verfügbar:
id | Beschreibung | Repository |
---|---|---|
Microsoft.NET.Sdk |
.NET SDK | https://github.com/dotnet/sdk |
Microsoft.NET.Sdk.Web |
Das .NET Web SDK | https://github.com/dotnet/sdk |
Microsoft.NET.Sdk.Razor |
Das .NET Razor SDK | https://github.com/dotnet/aspnetcore |
Microsoft.NET.Sdk.BlazorWebAssembly |
Das .NET Blazor WebAssembly SDK | https://github.com/dotnet/aspnetcore |
Microsoft.NET.Sdk.Worker |
.NET SDK für Workerdienste | |
Aspire.AppHost.Sdk |
Das .NET Aspire SDK | https://github.com/dotnet/aspire |
MSTest.Sdk |
MSTest SDK | https://github.com/microsoft/testfx |
Das .NET SDK ist das Basis-SDK für .NET. Die anderen SDKs verweisen auf das .NET SDK, und Projekten, die den anderen SDKs zugeordnet sind, stehen alle .NET SDK-Eigenschaften zur Verfügung. Das Web SDK ist z. B. sowohl vom .NET SDK als auch vom Razor SDK abhängig.
Sie können auch selbst ein SDK erstellen, das über NuGet verteilt werden kann.
Für Windows Forms- und Windows Presentation Foundation(WPF)-Projekte geben Sie das .NET SDK (Microsoft.NET.Sdk
) an und legen einige zusätzliche Eigenschaften in der Projektdatei fest. Weitere Informationen finden Sie unter Aktivierung des .NET SDK für die Desktopentwicklung.
Projektdateien
.NET-Projekte basieren auf dem MSBuild-Format. Projektdateien mit der Erweiterung .csproj für C#-Projekte und .fsproj für F#-Projekte, weisen das XML-Format auf. Das Stammelement einer MSBuild-Projektdatei ist das Element Project. Das Project
-Element besitzt ein optionales Sdk
-Attribut, das angibt, welches SDK (und welche Version) verwendet werden soll. Damit Sie die .NET-Tools verwenden und Ihren Code erstellen können, müssen Sie das Attribut Sdk
auf eine der IDs in der Tabelle Available SDKs (Verfügbare SDKs) festlegen.
<Project Sdk="Microsoft.NET.Sdk">
...
</Project>
Ab .NET Aspire 9 könnte im obigen Beispiel stattdessen das .NET Aspire SDK verwendet werden.
<Project Sdk="Microsoft.NET.Sdk">
<Sdk Name="Aspire.AppHost.Sdk" Version="9.0.0-rc.1.24511.1" />
<!-- Omitted for brevity... -->
</Project>
Weitere Informationen finden Sie unter .NET Aspire Tooling and Setup (.NET Aspire-Tools und -Einrichtung).
Um ein aus NuGet stammendes SDK anzugeben, schließen Sie die Version am Ende des Namens ein, oder geben Sie den Namen und die Version in der Datei global.json an.
<Project Sdk="MSBuild.Sdk.Extras/2.0.54">
...
</Project>
Das Sdk
-Element auf der obersten Ebene ist eine weitere Möglichkeit, das SDK anzugeben:
<Project>
<Sdk Name="Microsoft.NET.Sdk" />
...
</Project>
Wenn Sie mit einer dieser Möglichkeiten auf ein SDK verweisen, werden Projektdateien für .NET erheblich vereinfacht. Während der Auswertung des Projekts fügt MSBuild implizite Importe in der Projektdatei hinzu: im oberen Bereich für Sdk.props
, im unteren Bereich für 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>
Tipp
Auf einem Windows-Computer befinden sich die Dateien Sdk.props und Sdk.targets im Ordner %ProgramFiles%\dotnet\sdk\[version]\Sdks\Microsoft.NET.Sdk\Sdk.
Vorverarbeiten der Projektdatei
Mithilfe des Befehls dotnet msbuild -preprocess
können Sie ein vollständig erweitertes Projekt so anzeigen, wie es für MSBuild dargestellt wird, nachdem das SDK und die zugehörigen Ziele angegeben wurden. Die Option preprocess des Befehls dotnet msbuild
zeigt die importierten Dateien, ihre Quellen und ihren Beitrag zum Build, ohne das Projekt tatsächlich zu erstellen.
Wenn das Projekt mehrere Zielframeworks umfasst, geben Sie die Ergebnisse des Befehls nur für ein Framework aus, indem Sie dieses als MSBuild-Eigenschaft angeben. Zum Beispiel:
dotnet msbuild -property:TargetFramework=net8.0 -preprocess:output.xml
Standardmäßige Aufnahmen und Ausschlüsse
Die standardmäßigen Aufnahmen und Ausschlüsse für Compile
-Elemente, eingebettete Ressourcen und None
-Elemente sind im SDK definiert. Im Gegensatz zu SDK-Projekten, die nicht das .NET Framework als Ziel verwenden, müssen Sie diese Elemente nicht in Ihrer Projektdatei angeben, da die Standardwerte die meisten gängigen Anwendungsfälle abdecken. Durch dieses Verhalten wird die Projektdatei kleiner, verständlicher und kann bei Bedarf manuell bearbeitet werden.
Die folgende Tabelle zeigt, welche Elemente und welche Globs im .NET SDK enthalten bzw. nicht enthalten sind:
Element | Glob einschließen | Glob ausschließen | Glob entfernen |
---|---|---|---|
Compile | **/*.cs (oder andere Spracherweiterungen) | **/*.user; **/*.*proj; **/*.sln; **/*.vssscc | – |
EmbeddedResource | **/*.resx | **/*.user; **/*.*proj; **/*.sln; **/*.vssscc | – |
None | **/* | **/*.user; **/*.*proj; **/*.sln; **/*.vssscc | **/*.cs; **/*.resx |
Hinweis
Die Ordner ./bin
und ./obj
aus, die von den MSBuild-Eigenschaften $(BaseOutputPath)
und $(BaseIntermediateOutputPath)
dargestellt werden, sind standardmäßig von den Globs ausgeschlossen. Ausschlüsse werden durch die DefaultItemExcludes-Eigenschaft dargestellt.
Das .NET SDK für die Desktopentwicklung verfügt über weitere einzuschließende und auszuschließende Elemente für WPF. Weitere Informationen finden Sie im Abschnitt Standard-Includes und -Excludes für WPF.
Wenn Sie beliebige dieser Elemente explizit in Ihrer Projektdatei definieren, erhalten Sie wahrscheinlich eine NETSDK1022-Buildfehlermeldung. Informationen zum Beheben des Fehlers finden Sie unter NETSDK1022: Doppelte Elemente waren enthalten.
Implizite using-Anweisungen
Ab .NET 6 werden neuen C#-Projekten implizite global using
-Anweisungen hinzugefügt. Das bedeutet, dass Sie in diesen Namespaces definierte Typen verwenden können, ohne ihren vollqualifizierten Namen angeben oder manuell eine using
-Anweisung hinzufügen zu müssen. Der implizite Aspekt bezieht sich auf die Tatsache, dass die global using
-Anweisungen einer generierten Datei im obj-Verzeichnis des Projekts hinzugefügt werden.
Implizite global using
-Anweisungen werden für Projekte hinzugefügt, die eines der folgenden SDKs verwenden:
Microsoft.NET.Sdk
Microsoft.NET.Sdk.Web
Microsoft.NET.Sdk.Worker
Microsoft.NET.Sdk.WindowsDesktop
Eine global using
-Anweisung wird für jeden Namespace in einer Gruppe von Standardnamespaces hinzugefügt, die auf dem SDK des Projekts basieren. Diese Standardnamespaces sind in der folgenden Tabelle dargestellt.
SDK | Standardnamespaces |
---|---|
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-Namespaces 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-Namespaces Microsoft.Extensions.Configuration Microsoft.Extensions.DependencyInjection Microsoft.Extensions.Hosting Microsoft.Extensions.Logging |
Microsoft.NET.Sdk.WindowsDesktop (Windows Forms) | Microsoft.NET.Sdk-Namespaces System.Drawing System.Windows.Forms |
Microsoft.NET.Sdk.WindowsDesktop (WPF) | Microsoft.NET.Sdk-Namespaces System.IO entfernt System.Net.Http entfernt |
Wenn Sie dieses Feature deaktivieren oder implizite global using
-Anweisungen in einem vorhandenen C#-Projekt aktivieren möchten, können Sie dies über die MSBuild Eigenschaft ImplicitUsings
erreichen.
Sie können auch zusätzliche implizite global using
-Anweisungen hinzufügen, indem Sie Ihrer Projektdatei Using
-Elemente hinzufügen (oder Import
-Elemente für Visual Basic), beispielsweise:
<ItemGroup>
<Using Include="System.IO.Pipes" />
</ItemGroup>
Implizite Paketverweise
Wenn Ihr Projekt auf .NET Standard 1.0-2.0 abzielt, fügt das .NET SDK implizite Verweise auf bestimmte Metapakete hinzu. Ein Metapaket ist ein frameworkbasiertes Paket, das nur aus Abhängigkeiten von anderen Paketen besteht. Es wird auf der Grundlage der Zielfameworks, die in der Eigenschaft TargetFramework oder TargetFrameworks (Plural) Ihrer Projektdatei angegeben wurden, implizit auf Metapakete verwiesen.
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net462</TargetFrameworks>
</PropertyGroup>
Bei Bedarf können Sie implizite Paketverweise mithilfe der DisableImplicitFrameworkReferences-Eigenschaft deaktivieren und explizite Verweise nur auf die benötigten Frameworks oder Pakete hinzufügen.
Empfehlungen:
- Fügen Sie für .NET Framework oder .NET Standard 1.0-2.0 keine expliziten Verweise auf die
NETStandard.Library
-Metapakete über das<PackageReference>
-Element in Ihrer Projektdatei hinzu. Für .NET Standard 1.0-2.0-Projekte wird implizit auf diese Metapakete verwiesen. Wenn für .NET Framework-Projekte bei der Verwendung eines auf .NET Standard basierenden NuGet-Pakets eine bestimmte Version vonNETStandard.Library
benötigt wird, installiert NuGet diese automatisch. - Wenn Sie für .NET Standard 1.0-2.0 eine bestimmte Version des
NETStandard.Library
-Metapakets benötigen, können Sie die<NetStandardImplicitPackageVersion>
-Eigenschaft verwenden und die Version festlegen, die Sie benötigen.
Buildereignisse
Verwenden Sie in Projekten im SDK-Format ein MSBuild-Ziel namens PreBuild
oder PostBuild
, und legen Sie die Eigenschaft BeforeTargets
für PreBuild
oder die Eigenschaft AfterTargets
für PostBuild
fest.
<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>
Hinweis
- Sie können die MSBuild-Ziele beliebig benennen. Die Visual Studio-IDE erkennt jedoch
PreBuild
- undPostBuild
-Ziele. Wenn Sie diese Namen verwenden, können Sie also Befehle in der IDE bearbeiten. - Die Eigenschaften
PreBuildEvent
undPostBuildEvent
sollten in SDK-Projekten nicht verwendet werden, da Makros wie$(ProjectDir)
nicht aufgelöst werden. Beispielsweise wird der folgende Code nicht unterstützt:
<PropertyGroup>
<PreBuildEvent>"$(ProjectDir)PreBuildEvent.bat" "$(ProjectDir)..\" "$(ProjectDir)" "$(TargetDir)"</PreBuildEvent>
</PropertyGroup>
Anpassen des Builds
Es gibt verschiedene Möglichkeiten, einen Build anzupassen. Sie könnten eine Eigenschaft überschreiben, indem Sie sie als Argument an den msbuild- oder dotnet-Befehl übergeben. Sie können die Eigenschaft auch zur Projektdatei oder zu einer Directory.Build.props-Datei hinzufügen. Eine Liste mit nützlichen Eigenschaften für .NET-Projekte finden Sie in der MSBuild-Referenz für .NET Core SDK-Projekte.
Tipp
Eine einfache Möglichkeit, eine neue Datei Directory.Build.props über die Befehlszeile zu erstellen, besteht darin, den Befehl dotnet new buildprops
im Stammverzeichnis Ihres Repositorys zu verwenden.
Benutzerdefinierte Ziele
.NET-Projekte können benutzerdefinierte MSBuild-Ziele und -Eigenschaften für Projekte in Pakete packen, die das Paket nutzen. Verwenden Sie diese Art der Erweiterbarkeit, wenn Sie Folgendes vorhaben:
- Erweitern des Buildprozesses
- Zugreifen auf Artefakte des Buildprozesses, z. B. generierte Dateien
- Untersuchen einer Konfiguration, in der der Build aufgerufen wird
Sie fügen benutzerdefinierte Buildziele oder -eigenschaften hinzu, indem Sie Dateien im Format <package_id>.targets
oder <package_id>.props
(z. B.Contoso.Utility.UsefulStuff.targets
) im build-Ordner des Projekts platzieren.
Der XML-Code ist ein Codeausschnitt aus einer .csproj-Datei, die den Befehl dotnet pack
anweist, was paketiert werden soll. Das Element <ItemGroup Label="dotnet pack instructions">
platziert die Zieledateien innerhalb des Pakets in den Ordner build. Das Element <Target Name="CollectRuntimeOutputs" BeforeTargets="_GetPackageFiles">
platziert die Assemblys und .json-Dateien in den Ordner 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>
Damit ein benutzerdefiniertes Ziel in Ihrem Projekt genutzt werden kann, fügen Sie ein PackageReference
-Element hinzu, das auf das Paket und dessen Version zeigt. Im Gegensatz zu den Tools wird das benutzerdefinierte Zielpaket in die Abhängigkeiten des nutzenden Projekts eingeschlossen.
Sie können konfigurieren, wie das benutzerdefinierte Ziel genutzt werden soll. Da es sich um ein MSBuild-Ziel handelt, kann es von einem angegebenen Ziel abhängig sein, nach einem anderen Ziel ausgeführt werden oder mit dem Befehl dotnet msbuild -t:<target-name>
manuell aufgerufen werden. Wenn Sie jedoch ein besseres Benutzererlebnis bieten möchten, können Sie projektbezogene Tools und benutzerdefinierte Ziele kombinieren. In diesem Szenario akzeptiert das projektbezogene Tool alle erforderlichen Parameter und übersetzt diese in den erforderlichen dotnet msbuild
-Aufruf, der das Ziel ausführt. Sie sehen ein Beispiel dieser Art von Synergie im Repository mit den MVP Summit 2016 Hackathon-Beispielen im Projekt dotnet-packer
.