.NET SDKs für Projekte
Projekten für .NET Core und .NET 5 und höher ist ein 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.BlazorWebAssembly |
Das .NET Blazor WebAssembly SDK | |
Microsoft.NET.Sdk.Razor |
Das .NET Razor SDK | |
Microsoft.NET.Sdk.Worker |
.NET SDK für Workerdienste | |
Microsoft.NET.Sdk.WindowsDesktop |
.NET SDK für die Desktopentwicklung, das Windows Forms (WinForms) und Windows Presentation Foundation (WPF) enthält* | https://github.com/dotnet/winforms und https://github.com/dotnet/wpf |
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.
* Ab .NET 5 sollten Windows Forms- und Windows Presentation Foundation-Projekte (WPF) das .NET SDK (Microsoft.NET.Sdk
) anstelle von Microsoft.NET.Sdk.WindowsDesktop
angeben. Wenn Sie für diese Projekte TargetFramework
auf net5.0-windows
und UseWPF
oder UseWindowsForms
auf true
festlegen, wird das Windows Desktop SDK automatisch importiert. Wenn Ihr Projekt auf .NET 5 oder höher ausgerichtet ist und das Microsoft.NET.Sdk.WindowsDesktop
SDK angibt, wird die Buildwarnung NETSDK1137 ausgelöst.
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>
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=netcoreapp2.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 mehr einzuschließende und auszuschließende Elemente für WPF. Weitere Informationen finden Sie im Abschnitt Standard-Includes und -Excludes für WPF.
Buildfehler
Wenn Sie beliebige dieser Elemente explizit in Ihrer Projektdatei definieren, erhalten Sie wahrscheinlich eine „NETSDK1022“-Buildfehlermeldung ähnlich der folgenden:
Doppelte Compile-Elemente wurden eingeschlossen. Das .NET SDK enthält Compile-Elemente aus Ihrem Projektverzeichnis in der Standardeinstellung. Sie können diese Elemente aus Ihrer Projektdatei entfernen oder die Eigenschaft „EnableDefaultCompileItems“ auf FALSE festlegen, wenn Sie sie explizit in Ihrer Projektdatei einschließen möchten.
Doppelte EmbeddedResource-Elemente wurden eingeschlossen. Das .NET SDK enthält EmbeddedResource-Elemente aus Ihrem Projektverzeichnis in der Standardeinstellung. Sie können diese Elemente aus Ihrer Projektdatei entfernen oder die Eigenschaft „EnableDefaultEmbeddedResourceItems“ auf FALSE festlegen, wenn Sie sie explizit in Ihrer Projektdatei einschließen möchten.
Zum Beheben der Fehler führen Sie eine der folgenden Aktionen aus:
Entfernen Sie die expliziten
Compile
-,EmbeddedResource
- oderNone
-Elemente, die den in der vorherigen Tabelle aufgeführten impliziten Elementen entsprechen.Um jedes implizite Einbeziehen von Dateien zu deaktivieren, legen Sie die EnableDefaultItems-Eigenschaft auf
false
fest:<PropertyGroup> <EnableDefaultItems>false</EnableDefaultItems> </PropertyGroup>
Wenn Sie Dateien angeben möchten, die mit Ihrer Anwendung veröffentlicht werden sollen, können Sie weiterhin die bekannten MSBuild-Mechanismen dafür verwenden, wie etwa das
Content
-Element.Deaktivieren Sie selektiv nur
Compile
-,EmbeddedResource
- oderNone
-Globs, indem Sie die EnableDefaultCompileItems-, EnableDefaultEmbeddedResourceItems- oder EnableDefaultNoneItems-Eigenschaft auffalse
festlegen:<PropertyGroup> <EnableDefaultCompileItems>false</EnableDefaultCompileItems> <EnableDefaultEmbeddedResourceItems>false</EnableDefaultEmbeddedResourceItems> <EnableDefaultNoneItems>false</EnableDefaultNoneItems> </PropertyGroup>
Wenn Sie nur
Compile
-Globs deaktivieren, zeigt der Projektmappen-Explorer in Visual Studio die *.cs-Elemente eingeschlossen alsNone
-Elemente weiterhin als Teil des Projekts an. Um das impliziteNone
-Glob zu deaktivieren, legen Sie auchEnableDefaultNoneItems
auffalse
fest.
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 | 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.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
Für .NET Core 1.0-2.2 oder .NET Standard 1.0-2.0 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 des/der Zielfameworks, das/die in der TargetFramework- oder TargetFrameworks-Eigenschaft Ihrer Projektdatei angegeben wurde/n, implizit auf Metapakete verwiesen.
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup>
<PropertyGroup>
<TargetFrameworks>netcoreapp2.1;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, .NET Core 1.0-2.2 oder .NET Standard 1.0-2.0 keine expliziten Verweise auf die
Microsoft.NETCore.App
- oderNETStandard.Library
-Metapakete über das<PackageReference>
-Element in Ihrer Projektdatei hinzu. Für .NET Core 1.0-2.2- und .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 Core 1.0-2.2 eine bestimmte Version der Runtime benötigen, sollten Sie die
<RuntimeFrameworkVersion>
-Eigenschaft in Ihrem Projekt (z. B.1.0.4
) verwenden, anstatt auf Metapakete zu verweisen. Sie benötigen z. B. möglicherweise eine bestimmte Patchversion der 1.0.0 LTS-Runtime, wenn Sie eigenständige Bereitstellungen verwenden. - 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önnen eine Eigenschaft überschreiben, indem Sie sie als Argument an einen 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.
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
.