Neuerungen in .NET Core 3.0

In diesem Artikel werden Neuerungen in .NET Core 3.0 beschrieben. Eine der wichtigsten Verbesserungen ist die Unterstützung für Windows-Desktopanwendungen (nur Windows). Mit der .NET Core 3.0 SDK-Komponente Windows Desktop können Sie Ihre Windows Forms- und WPF-Anwendungen (Windows Presentation Foundation) portieren. Die Windows Desktop-Komponente wird ausdrücklich nur für Windows unterstützt und ist nur unter Windows enthalten. Weitere Informationen finden Sie im Abschnitt Windows-Desktop weiter unten in diesem Artikel.

.NET Core 3.0 bietet Unterstützung für C# 8.0. Es wird dringend empfohlen, Visual Studio 2019, Version 16.3 oder höher, oder Visual Studio Code mit der neuesten C#-Erweiterung zu verwenden.

Sie können .NET Core 3.0 jetzt für Windows, macOS oder Linux herunterladen und sofort starten.

Weitere Informationen zu diesem Release finden Sie unter Ankündigung von .NET Core 3.0.

.NET Core 3.0 RC1 wurde von Microsoft als produktionsbereit betrachtet und vollständig unterstützt. Wenn Sie eine Vorschauversion verwenden, müssen Sie für die weitere Unterstützung zur Version RTM wechseln.

Sprachverbesserungen in C# 8.0

C# 8.0 ist ebenfalls Teil dieses Releases, welches das Feature mit Referenztypen, die NULL-Werte zulassen, asynchrone Datenströme und weitere Muster enthält. Weitere Informationen zu Features von C# 8.0 finden Sie unter Neues in C# 8.0.

Tutorials im Zusammenhang mit den C# 8.0-Sprachfeatures:

Es wurden Spracherweiterungen hinzugefügt, um die folgenden API-Features zu unterstützen:

.NET Standard 2.1

.NET Core 3.0 implementiert .NET Standard 2.1. Dennoch generiert die Standardvorlage dotnet new classlib weiterhin ein Projekt für .NET Standard 2.0. Ändern Sie für .NET Standard 2.1 in Ihrer Projektdatei die TargetFramework-Eigenschaft in netstandard2.1:

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

  <PropertyGroup>
    <TargetFramework>netstandard2.1</TargetFramework>
  </PropertyGroup>

</Project>

Wenn Sie Visual Studio verwenden, benötigen Sie Visual Studio 2019, da Visual Studio 2017 .NET Standard 2.1 und .NET Core 3.0 nicht unterstützt.

Kompilieren/bereitstellen

Standardmäßig ausführbare Dateien

.NET Core erstellt die frameworkabhängigen ausführbaren Dateien jetzt standardmäßig. Dieses Verhalten ist neu für Anwendungen, die eine global installierte Version von .NET Core verwenden. Vorher produzierten nur eigenständige Bereitstellungen eine ausführbare Datei.

Während dotnet build oder dotnet publish wird eine ausführbare Datei (appHost) erstellt, die der Umgebung und Plattform des von Ihnen verwendeten SDKs entspricht. Diese ausführbaren Dateien bieten Ihnen die gleichen Möglichkeiten wie andere native ausführbare Dateien, wie z.B.:

  • Sie können die ausführbare Datei doppelklicken.
  • Sie können die Anwendung direkt aus einer Eingabeaufforderung starten, z.B. myapp.exe unter Windows und ./myapp unter Linux und MacOS.

macOS-appHost und -Notarisierung

nur unter macOS

Ab dem notarisierten .NET Core SDK 3.0 für macOS ist die Einstellung zum Erstellen einer ausführbaren Standarddatei („appHost“) standardmäßig deaktiviert. Weitere Informationen finden Sie unter macOS Catalina-Notarisierung und die Auswirkungen auf .NET Core-Downloads und -Projekte.

Wenn die appHost-Einstellung aktiviert ist, erzeugt .NET Core eine native ausführbare Mach-O-Datei, wenn Sie einen Build- oder Veröffentlichungsprozess ausführen. Ihre App wird im Kontext von appHost ausgeführt, wenn sie mit dem Befehl dotnet run über den Quellcode oder durch direktes Starten der ausführbaren Mach-O-Datei ausgeführt wird.

Ohne die appHost-Datei können Benutzer eine frameworkabhängige App nur mit dem Befehl dotnet <filename.dll> starten. Es wird immer eine appHost-Datei erstellt, wenn Sie Ihre App eigenständig veröffentlichen.

Sie können die appHost-Datei entweder auf Projektebene konfigurieren oder für einen spezifischen dotnet-Befehl mit dem -p:UseAppHost-Parameter aktivieren:

  • Projektdatei

    <PropertyGroup>
      <UseAppHost>true</UseAppHost>
    </PropertyGroup>
    
  • Befehlszeilenparameter

    dotnet run -p:UseAppHost=true
    

Weitere Informationen über die UseAppHost-Einstellung finden Sie unter MSBuild-Eigenschaften für Microsoft.NET.Sdk.

Ausführbare Einzeldateien

Der dotnet publish-Befehl unterstützt das Verpacken der App in einer plattformspezifischen ausführbaren Einzeldatei. Die ausführbare Datei ist selbstextrahierend und enthält alle Abhängigkeiten (einschließlich der nativen), die zum Ausführen der App erforderlich sind. Beim ersten Ausführen der App wird die Anwendung in ein Verzeichnis extrahiert, das auf dem Namen und dem Buildbezeichner der App basiert. Der Start ist beim erneuten Ausführen der App schneller. Die Anwendung muss sich nicht selbst ein zweites Mal extrahieren, sofern keine neue Version verwendet wird.

Legen Sie zum Veröffentlichen einer einzelnen ausführbaren Datei PublishSingleFile in Ihrem Projekt oder in der Befehlszeile mit dem dotnet publish-Befehl fest:

<PropertyGroup>
  <RuntimeIdentifier>win10-x64</RuntimeIdentifier>
  <PublishSingleFile>true</PublishSingleFile>
</PropertyGroup>

- oder -

dotnet publish -r win10-x64 -p:PublishSingleFile=true

Weitere Informationen zum Veröffentlichen einzelner Dateien finden Sie im Einzeldatei-Bundler-Entwurfsdokument.

Trimmen von Assemblys

Das.NET Core 3.0 SDK bietet ein Tool, das die Größe von Apps reduzieren kann, indem es IL analysiert und ungenutzte Assemblys trimmt.

Eigenständige Apps enthalten alles, was zum Ausführen Ihres Codes benötigt wird, ohne dass .NET auf dem Hostcomputer installiert sein muss. Allerdings benötigt die App oft nur eine kleine Teilmenge des Frameworks, um zu funktionieren, sodass andere ungenutzte Bibliotheken entfernt werden können.

.NET Core bietet nun eine Einstellung, die das Tool IL Linker verwendet, um die IL Ihrer App zu untersuchen. Dieses Tool erkennt, welcher Code erforderlich ist, und trimmt dann ungenutzte Bibliotheken. Es kann die Bereitstellungsgröße einiger Apps deutlich reduzieren.

Fügen Sie die Einstellung <PublishTrimmed> zu Ihrem Projekt hinzu, und veröffentlichen Sie eine eigenständige App, um dieses Tool zu aktivieren:

<PropertyGroup>
  <PublishTrimmed>true</PublishTrimmed>
</PropertyGroup>
dotnet publish -r <rid> -c Release

Als Beispiel erreicht die inbegriffene Standardvorlage für neue Konsolenprojekte „hello world“ bei ihrer Veröffentlichung eine Größe von ca.70 MB. Mithilfe von <PublishTrimmed> wird diese Größe auf ca. 30 MB reduziert.

Wichtig ist die Tatsache, dass Anwendungen oder Frameworks (einschließlich ASP.NET Core und WPF), die Reflektion oder verwandte dynamische Funktionen verwenden, nach dem Trimmen oft nicht mehr funktionieren. Dies ist der Fall, weil der Linker von diesem dynamischen Verhalten nichts weiß und nicht bestimmen kann, welche Frameworktypen für die Reflektion benötigt werden. Das Tool IL Linker kann so konfiguriert werden, dass es sich dieses Szenarios bewusst ist.

Nach dem Trimmen müssen Sie Ihre App unbedingt testen.

Weitere Informationen zum Tool IL Linker finden Sie in der Dokumentation oder im Repository mono/linker.

Mehrstufig Kompilierung

Die mehrstufige Kompilierung (Tiered Compilation, TC) ist bei .NET Core 3.0 standardmäßig aktiviert. Dieses Feature ermöglicht der Runtime, den Just-In-Time-Compiler (JIT) adaptiver zu nutzen, um eine bessere Leistung zu erzielen.

Der Hauptvorteil der mehrstufigen Kompilierung (TC, Tiered Compilation) besteht darin, dass sie zwei Methoden zur Just-in-Time-Kompilierung bietet: in einer Stufe mit geringerer Qualität, die aber schneller ist, oder in einer Stufe mit höherer Qualität, die aber langsamer ist. Die Qualität bezieht sich darauf, wie gut die Methode optimiert ist. Die TC verbessert die Leistung einer Anwendung, während sie verschiedene Phasen der Ausführung vom Start bis zum stabilen Zustand durchläuft. Wenn die TC deaktiviert ist, wird jede Methode auf eine einzige Weise kompiliert, die auf eine stabile Leistung gegenüber der Startleistung ausgerichtet ist.

Wenn TC aktiviert ist, gilt beim Start einer App das folgende Verhalten für die Methodenkompilierung:

  • Wenn die Methode über AOT-kompilierten Code oder ReadyToRun verfügt, wird der zuvor generierte Code verwendet.
  • Andernfalls wird die Methode mit JIT kompiliert. In der Regel sind diese Methoden Generics über Werttypen.
    • Quick JIT erzeugt schneller Code geringerer Qualität (oder weniger optimiert). In .NET Core 3.0 ist Quick JIT standardmäßig für Methoden aktiviert, die keine Schleifen enthalten. Während des Starts wird dies bevorzugt.
    • Die vollständig optimierte Just-In-Time-Kompilierung erzeugt Code höherer Qualität (oder besser optimierten Code), ist aber langsamer. Für Methoden, bei denen die schnelle JIT-Kompilierung nicht verwendet werden würde (beispielsweise dann, wenn die Methode das Attribut MethodImplOptions.AggressiveOptimization aufweist), wird die vollständig optimierte JIT-Kompilierung verwendet.

Bei häufig aufgerufenen Methoden erzeugt der Just-in-Time-Compiler schließlich vollständig optimierten Code im Hintergrund. Der optimierte Code ersetzt dann den vorkompilierten Code für diese Methode.

Code, der von der schnellen JIT-Kompilierung generiert wurde, wird möglicherweise langsamer ausgeführt, belegt mehr Arbeitsspeicher oder nutzt mehr Stapelspeicher. Wenn es Probleme gibt, können Sie Quick JIT mit dieser MSBuild-Eigenschaft in der Projektdatei deaktivieren:

<PropertyGroup>
  <TieredCompilationQuickJit>false</TieredCompilationQuickJit>
</PropertyGroup>

Verwenden Sie diese MSBuild-Eigenschaft in der Projektdatei, um die TC vollständig zu deaktivieren:

<PropertyGroup>
  <TieredCompilation>false</TieredCompilation>
</PropertyGroup>

Tipp

Wenn Sie diese Einstellungen in der Projektdatei ändern, müssen Sie möglicherweise einen bereinigten Build durchführen, damit die neuen Einstellungen reflektiert werden. (Löschen Sie die Verzeichnisse obj und bin, und erstellen Sie diese neu).

Weitere Informationen zum Konfigurieren der Kompilierung zur Laufzeit finden Sie unter Laufzeitkonfigurationsoptionen für die Kompilierung.

ReadyToRun-Images

Sie können die Startzeit Ihrer.NET Core-Anwendung beschleunigen, indem Sie Ihre Anwendungsassemblys im R2R-Format (ReadyToRun) kompilieren. R2R ist eine Form der AOT-Kompilierung (Ahead-Of-Time).

R2R-Binärdateien verbessern die Startleistung, indem sie den Arbeitsaufwand des JIT-Compilers (Just-in-time) reduzieren, der anfällt, wenn Ihre Anwendung geladen wird. Die Binärdateien enthalten ähnlichen nativen Code im Vergleich zu dem, was der JIT-Compiler produzieren würde. R2R-Binärdateien sind jedoch größer, da sie sowohl IL-Code (Intermediate Language, Zwischensprache), der für einige Szenarios noch benötigt wird, als auch die native Version des gleichen Codes enthalten. R2R ist nur verfügbar, wenn Sie eine eigenständige Anwendung veröffentlichen, die eine bestimmte Laufzeitumgebung (RID) wie Linux x64 oder Windows x64 als Ziel hat.

Gehen Sie folgendermaßen vor, um Ihr Projekt als „ReadyToRun“ (Bereit zur Ausführung) zu kompilieren:

  1. Fügen Sie die <PublishReadyToRun>-Einstellung in Ihr Projekt ein.

    <PropertyGroup>
      <PublishReadyToRun>true</PublishReadyToRun>
    </PropertyGroup>
    
  2. Veröffentlichen Sie eine eigenständige App. Dieser Befehl erstellt beispielsweise eine eigenständige App für die 64-Bit-Version von Windows:

    dotnet publish -c Release -r win-x64 --self-contained
    

Plattformübergreifende bzw. architekturbezogene Einschränkungen

Der ReadyToRun-Compiler unterstützt derzeit nicht die versionsübergreifende Angabe von Zielen. Die Kompilierung muss für ein bestimmtes Ziel erfolgen. Wenn Sie beispielsweise R2R-Images für Windows x64 benötigen, müssen Sie den Veröffentlichungsbefehl in dieser Umgebung ausführen.

Ausnahmen für die versionsübergreifende Angabe von Zielen:

  • Windows x64 kann zum Kompilieren von Windows Arm32-, Arm64- und x86-Images verwendet werden.
  • Windows x86 kann zum Kompilieren von Windows Arm32-Images verwendet werden.
  • Linux X64 kann zum Kompilieren von Linux Arm32- und Arm64-Images verwendet werden.

Weitere Informationen finden Sie auf der Seite zu Bereit zur Ausführung.

Runtime/SDK

Runtimerollforward der Hauptversion

Mit .NET Core 3.0 wird ein Aktivierungsfeature eingeführt, das Ihrer App ein Rollforward auf die neueste Hauptversion von .NET Core ermöglicht. Darüber hinaus wurde eine neue Einstellung hinzugefügt, um zu steuern, wie ein Rollforward auf Ihre App angewendet wird. Diese kann folgendermaßen konfiguriert werden:

  • Projektdateieigenschaft: RollForward
  • Runtimekonfigurationsdatei-Eigenschaft: rollForward
  • Umgebungsvariable: DOTNET_ROLL_FORWARD
  • Befehlszeilenargument: --roll-forward

Einer der folgenden Werte muss angegeben werden. Wenn die Einstellung ausgelassen wird, ist Minor die Standardeinstellung.

  • LatestPatch
    Rollforward zur höchsten Patchversion. Dies deaktiviert ein Rollforward zur Nebenversion.
  • Minor
    Rollforward zur niedrigsten höheren Nebenversion, wenn die angeforderte Nebenversion nicht vorhanden ist. Wenn die angeforderte Nebenversion vorhanden ist, wird die LatestPatch-Richtlinie verwendet.
  • Major
    Rollforward zur niedrigsten höheren Hauptversion – und niedrigsten Nebenversion, wenn die angeforderte Hauptversion nicht vorhanden ist. Wenn die angeforderte Hauptversion vorhanden ist, wird die Minor-Richtlinie verwendet.
  • LatestMinor
    Rollforward zur höchsten Nebenversion – auch dann, wenn die angeforderte Nebenversion vorhanden ist. Für Komponentenhostingszenarien vorgesehen.
  • LatestMajor
    Rollforward zur höchsten Hauptversion und höchsten Nebenversion – auch dann, wenn die angeforderte Hauptversion vorhanden ist. Für Komponentenhostingszenarien vorgesehen.
  • Deaktivieren
    Kein Rollforward. Nur Binden an angegebene Version. Diese Richtlinie wird nicht zur allgemeinen Verwendung empfohlen, da sie die Möglichkeit eines Rollforwards zu den neuesten Patches ausschließt. Dieser Wert wird nur zu Testzwecken empfohlen.

Abgesehen von der Disable-Einstellung verwenden alle Einstellungen die höchste verfügbare Patchversion.

Wenn die angeforderte Version (wie in .runtimeconfig.json für die Anwendung angegeben) eine endgültige Produktversion ist, werden standardmäßig nur endgültige Produktversionen für das Rollforward berücksichtigt. Vorabversionen werden ignoriert. Wenn keine passende endgültige Produktversion vorhanden ist, werden Vorabversionen berücksichtigt. Dieses Verhalten kann durch Festlegen von DOTNET_ROLL_FORWARD_TO_PRERELEASE=1 geändert werden. In diesem Fall werden immer alle Versionen berücksichtigt.

Build kopiert Abhängigkeiten

Der dotnet build-Befehl kopiert jetzt NuGet-Abhängigkeiten für Ihre Anwendung aus dem NuGet-Cache in den Buildausgabeordner. Bisher wurde Abhängigkeiten nur als Teil von dotnet publish kopiert.

Es gibt einige Vorgänge, wie das Kürzen und Veröffentlichen von Razor-Seiten, die noch veröffentlicht werden müssen.

Lokale Tools

Mit .NET Core 3.0 werden lokale Tools eingeführt. Lokale Tools ähneln globalen Tools, sind aber mit einem bestimmten Speicherort auf dem Datenträger verknüpft. Lokale Tools sind nicht global verfügbar und werden als NuGet-Pakete verteilt.

Lokale Tools basieren auf einer Manifestdatei dotnet-tools.json in Ihrem aktuellen Verzeichnis. In dieser Manifestdatei werden die Tools festgelegt, die im Verzeichnis und in den Unterverzeichnissen verfügbar sind. Sie können die Manifestdatei mit dem Code verteilen, um sicherzustellen, dass jeder Benutzer, der mit Ihrem Code arbeitet, dieselben Tools wiederherstellen und verwenden kann.

Für sowohl globale als auch lokale Tools ist eine kompatible Version der Runtime erforderlich. Die meisten Tools führen derzeit NuGet.org target .NET Core Runtime 2.1 aus. Um diese Tools global oder lokal zu installieren, müssten Sie weiterhin die NET Core 2.1-Runtime installieren.

Neue global.json-Optionen

Die Datei global.json verfügt über neue Optionen, die mehr Flexibilität bei der Definition der verwendeten .NET Core SDK-Version bieten. Folgende neue Optionen sind verfügbar:

  • allowPrerelease: Gibt an, ob der SDK-Resolver bei der Auswahl der zu verwendenden SDK-Version Vorabversionen berücksichtigen soll.
  • rollForward: Gibt die Rollforwardrichtlinie an, die beim Auswählen einer SDK-Version verwendet werden soll, entweder als Fallback, wenn eine bestimmte SDK-Version fehlt, oder als Anweisung, damit eine höhere Version verwendet wird.

Weitere Informationen zu den Änderungen, einschließlich Standardwerten, unterstützten Werten und neuen Abgleichsregeln, finden Sie unter global.json: Übersicht.

Kleinere Garbage Collection-Heapgrößen

Die Standardheapgröße des Garbage Collectors wurde reduziert, sodass .NET Core weniger Arbeitsspeicher benötigt. Diese Änderung entspricht eher dem Zuordnungsbudget von Generation 0 mit modernen Prozessorcachegrößen.

Garbage Collection: Unterstützung von „Large Pages“

„Large Pages“ (umfangreiche Seiten, unter Linux auch als „Huge Pages“ bekannt) ist eine Funktion, die dem Betriebssystem ermöglicht, Speicherbereiche einzurichten, die die native Seitengröße (häufig 4KB) überschreiten, um die Leistung der Anwendung zu verbessern, die diese große Seiten anfordert.

Der Garbage Collector kann nun mit der Einstellung GCLargePages als Aktivierungsfeature zum Auswählen der Zuordnung großer Seiten auf Windows konfiguriert werden.

Windows Desktop und COM

Windows Installer von .NET Core SDK

Das MSI-Installationsprogramm für Windows wurde ab .NET Core 3.0 geändert. Die SDK-Installer aktualisieren nun vorhandene Releases von SDK-Featuregruppen. Featuregruppen werden in den Hundertergruppen des Patchabschnitts der Versionsnummer definiert. 3.0.101 und 3.0.201 sind beispielsweise Versionen in zwei verschiedenen Featuregruppen, während sich 3.0.101 und 3.0.199 in derselben Featuregruppe befinden. Wenn .NET Core SDK 3.0.101 installiert wird, wird .NET Core SDK 3.0.100 (sofern vorhanden) vom Computer entfernt. Wenn .NET Core SDK 3.0.200 auf demselben Computer installiert ist, wird .NET Core SDK 3.0.101 nicht entfernt.

Weitere Informationen zur Versionsverwaltung finden Sie unter Übersicht über die .NET Core-Versionsverwaltung.

Windows-Desktop

.NET Core 3.0 unterstützt die Windows-Desktopanwendungen mit Windows Presentation Foundation (WPF) und Windows Forms. Diese Frameworks unterstützt auch die Verwendung moderner Steuerelemente und des Fluent-Stils aus der Windows-UI-XAML-Bibliothek (WinUI) über XAML-Inseln.

Die Windows Desktop-Komponente ist Teil des Windows .NET Core 3.0 SDK.

Mit dem folgenden dotnet-Befehl können Sie eine neue WPF- oder Windows Forms-Anwendung erstellen:

dotnet new wpf
dotnet new winforms

Neu in Visual Studio 2019 sind Vorlagen für die Option Neues Projekt für Windows Forms und WPF in .NET Core 3.0.

Weitere Informationen zum Portieren einer vorhandenen .NET Framework-Anwendung finden Sie unter Portieren von WPF-Projekten und Portieren von Windows Forms-Projekten.

WinForms mit hohem DPI-Wert

.NET Core-Windows Forms-Anwendungen können den Modus für hohe DPI-Werte mit Application.SetHighDpiMode(HighDpiMode) festlegen. Die SetHighDpiMode-Methode legt den entsprechenden Modus für hohe DPI-Werte fest, sofern er nicht mit anderen Mitteln wie App.Manifest oder „P/Invoke“ vor dem Application.Run festgelegt wurde.

Die möglichen highDpiMode-Werte, wie durch die System.Windows.Forms.HighDpiMode-Enumeration ausgedrückt, sind:

  • DpiUnaware
  • SystemAware
  • PerMonitor
  • PerMonitorV2
  • DpiUnawareGdiScaled

Weitere Informationen zu hohen DPI-Werten finden Sie unter Entwicklung von Desktopanwendungen mit hohen DPI-Werten unter Windows.

Erstellen von COM-Komponenten

Unter Windows können Sie jetzt COM-aufrufbare verwaltete Komponenten erstellen. Diese Funktion ist für die Verwendung von .NET Core mit COM-Add-in-Modellen und auch zur Parität mit .NET Framework wichtig.

Im Gegensatz zu .NET Framework, wo mscoree.dll als COM-Server verwendet wurde, fügt .NET Core dem bin-Verzeichnis eine native Startprogramm-DLL hinzu, wenn Sie Ihre COM-Komponente erstellen.

Ein Beispiel für das Erstellen einer COM‑Komponente und ihre Verwendung finden Sie in der COM-Demo.

Native Windows-Interop-API

Windows stellt eine umfassende native API mit grundlegenden C-APIs (ohne C++-Features), COM und WinRT bereit. Während .NET Core P/Invoke unterstützt, fügt .NET Core 3.0 die Fähigkeit zum CoCreate von COM-APIs und Aktivieren von WinRT-APIs hinzu. Ein Codebeispiel finden Sie in der Excel-Demo.

MSIX-Bereitstellung

MSIX ist ein neues Windows-Anwendungspaketformat. Es kann zum Bereitstellen von .NET Core 3.0-Desktopanwendungen auf Windows 10 verwendet werden.

In Visual Studio 2019 können mit dem enthaltenen Paketerstellungsprojekt für Windows-Anwendungen MSIX-Pakete mit eigenständigen .NET Core-Anwendungen erstellt werden.

Die unterstützten Laufzeiten müssen in der <RuntimeIdentifiers>-Eigenschaft der .NET Core-Projektdatei angegeben werden:

<RuntimeIdentifiers>win-x86;win-x64</RuntimeIdentifiers>

Verbesserungen für Linux

SerialPort für Linux

.NET Core 3.0 bietet grundlegende Unterstützung für System.IO.Ports.SerialPort unter Linux.

Bisher unterstützte .NET Core nur die Verwendung von SerialPort auf Windows.

Weitere Informationen zur eingeschränkten Unterstützung für den seriellen Anschluss unter Linux finden Sie unter GitHub-Issue 33146.

Arbeitsspeicherlimits bei Docker und Cgroup

Die Ausführung von .NET Core 3.0 unter Linux mit Docker funktioniert besser mit Cgroup-Arbeitsspeicherlimits. Das Ausführen eines Docker-Containers mit Arbeitsspeicherlimits, z.B. mit docker run -m, ändert das Verhalten von .NET Core.

  • Standardmäßige Heapgröße des Garbage Collectors (GC): maximal 20MB oder 75% des Arbeitsspeicherlimits für den Container.
  • Die explizite Größe kann als absolute Anzahl oder Prozentsatz des Cgroup-Limits festgelegt werden.
  • Die minimale reservierte Segmentgröße pro GC-Heap beträgt 16MB. Diese Größe reduziert die Anzahl der Heaps, die auf Computern erstellt werden.

GPIO-Unterstützung für Raspberry Pi

Über NuGet können nun zwei Pakete für die GPIO-Programmierung bezogen werden:

Die GPIO-Pakete enthalten APIs für GPIO-, SPI-, I2C- und PWM-Geräte. Das IoT-Bindungenpaket enthält Gerätebindungen. Weitere Informationen finden Sie im GitHub-Repository zu Geräten.

Unterstützung für Arm64 unter Linux

.NET Core 3.0 fügt Unterstützung für Arm64 unter Linux hinzu. Der primäre Anwendungsfall für Arm64 sind derzeit IoT-Szenarien. Weitere Informationen finden Sie unter .NET Core Arm64 Status.

Dockerimages für .NET Core in Arm64 sind für Alpine, Debian und Ubuntu verfügbar.

Hinweis

Unterstützung für macOS Arm64-Betriebssysteme („Apple Silicon“) und Windows Arm64-Betriebssysteme wurde später in .NET 6 hinzugefügt.

Sicherheit

TLS 1.3 & OpenSSL 1.1.1 auf Linux

.NET Core nutzt nun die Unterstützung von TLS 1.3 in OpenSSL 1.1.1.1, wenn es in einer bestimmten Umgebung verfügbar ist. Mit TLS 1.3:

  • Verbindungszeiten werden durch Reduzierung der erforderlichen Roundtrips zwischen Client und Server verbessert.
  • Verbesserte Sicherheit wg. Entfernen verschiedener veralteter und unsicherer kryptografischer Algorithmen.

Sofern verfügbar, verwendet .NET Core 3.0 OpenSSL 1.1.1, OpenSSL 1.1.0 oder OpenSSL 1.0.2 auf einem Linuxsystem. Wenn OpenSSL 1.1.1 verfügbar ist, verwendet sowohl der System.Net.Security.SslStream- als auch System.Net.Http.HttpClient-Typ TLS 1.3 (vorausgesetzt, dass Client und Server TLS 1.3 unterstützen).

Das folgende Beispiel für C# 8.0 veranschaulicht das Herstellen der Verbindung von .NET Core 3.0 auf Ubuntu 18.10 mit https://www.cloudflare.com:

using System;
using System.Net.Security;
using System.Net.Sockets;
using System.Threading.Tasks;

namespace whats_new
{
    public static class TLS
    {
        public static async Task ConnectCloudFlare()
        {
            var targetHost = "www.cloudflare.com";

            using TcpClient tcpClient = new TcpClient();

            await tcpClient.ConnectAsync(targetHost, 443);

            using SslStream sslStream = new SslStream(tcpClient.GetStream());

            await sslStream.AuthenticateAsClientAsync(targetHost);
            await Console.Out.WriteLineAsync($"Connected to {targetHost} with {sslStream.SslProtocol}");
        }
    }
}

Kryptografieverschlüsselungen

.NET 3.0 fügt Unterstützung für die Verschlüsselungsmodi AES-GCM und AES-CCM hinzu, die jeweils mit System.Security.Cryptography.AesGcm bzw. System.Security.Cryptography.AesCcm implementiert werden. Beide Algorithmen sind AEAD-Algorithmen (Authenticated Encryption with Association Data).

Der folgende Code veranschaulicht die Verwendung der AesGcm-Verschlüsselung zum Verschlüsseln und Entschlüsseln von Zufallsdaten.

using System;
using System.Linq;
using System.Security.Cryptography;

namespace whats_new
{
    public static class Cipher
    {
        public static void Run()
        {
            // key should be: pre-known, derived, or transported via another channel, such as RSA encryption
            byte[] key = new byte[16];
            RandomNumberGenerator.Fill(key);

            byte[] nonce = new byte[12];
            RandomNumberGenerator.Fill(nonce);

            // normally this would be your data
            byte[] dataToEncrypt = new byte[1234];
            byte[] associatedData = new byte[333];
            RandomNumberGenerator.Fill(dataToEncrypt);
            RandomNumberGenerator.Fill(associatedData);

            // these will be filled during the encryption
            byte[] tag = new byte[16];
            byte[] ciphertext = new byte[dataToEncrypt.Length];

            using (AesGcm aesGcm = new AesGcm(key))
            {
                aesGcm.Encrypt(nonce, dataToEncrypt, ciphertext, tag, associatedData);
            }

            // tag, nonce, ciphertext, associatedData should be sent to the other part

            byte[] decryptedData = new byte[ciphertext.Length];

            using (AesGcm aesGcm = new AesGcm(key))
            {
                aesGcm.Decrypt(nonce, ciphertext, tag, decryptedData, associatedData);
            }

            // do something with the data
            // this should always print that data is the same
            Console.WriteLine($"AES-GCM: Decrypted data is {(dataToEncrypt.SequenceEqual(decryptedData) ? "the same as" : "different than")} original data.");
        }
    }
}

Importieren/Exportieren kryptografischer Schlüssel

.NET Core 3.0 unterstützt das Importieren und Exportieren der asymmetrischen öffentlichen und privaten Schlüssel aus den Standardformaten. Sie müssen kein X.509-Zertifikat verwenden.

Alle Schlüsseltypen wie RSA, DSA, ECDsa und ECDiffieHellman unterstützen die folgenden Formate:

  • Öffentlicher Schlüssel

    • X.509 SubjectPublicKeyInfo
  • Privater Schlüssel

    • PKCS#8 PrivateKeyInfo
    • PKCS#8 EncryptedPrivateKeyInfo

RSA-Schlüsseln unterstützen auch:

  • Öffentlicher Schlüssel

    • PKCS#1 RSAPublicKey
  • Privater Schlüssel

    • PKCS#1 RSAPrivateKey

Die Exportmethoden erstellen DER-kodierte Binärdaten, und die Importmethoden erwarten dasselbe. Wenn ein Schlüssel im textfreundlichen PEM-Format gespeichert ist, muss der Anrufer den Inhalt base64-dekodieren, bevor er eine Importmethode aufruft.

using System;
using System.Security.Cryptography;

namespace whats_new
{
    public static class RSATest
    {
        public static void Run(string keyFile)
        {
            using var rsa = RSA.Create();

            byte[] keyBytes = System.IO.File.ReadAllBytes(keyFile);
            rsa.ImportRSAPrivateKey(keyBytes, out int bytesRead);

            Console.WriteLine($"Read {bytesRead} bytes, {keyBytes.Length - bytesRead} extra byte(s) in file.");
            RSAParameters rsaParameters = rsa.ExportParameters(true);
            Console.WriteLine(BitConverter.ToString(rsaParameters.D));
        }
    }
}

PKCS#8-Dateien können mit System.Security.Cryptography.Pkcs.Pkcs8PrivateKeyInfo überprüft werden, und PFX/PKCS#12-Dateien mit System.Security.Cryptography.Pkcs.Pkcs12Info. PFX/PKCS#12-Dateien können mit System.Security.Cryptography.Pkcs.Pkcs12Builder bearbeitet werden.

Änderungen der .NET Core 3.0-API

Bereiche und Indizes

Der neue System.Index-Typ kann für die Indizierung verwendet werden. Sie können einen aus einem int erstellen, der vom Anfang aus zählt, oder mit einem Präfix-^-Operator (C#), der vom Ende aus zählt:

Index i1 = 3;  // number 3 from beginning
Index i2 = ^4; // number 4 from end
int[] a = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
Console.WriteLine($"{a[i1]}, {a[i2]}"); // "3, 6"

Es gibt auch einen System.Range-Typ, der aus zwei Index-Werten besteht, einen für den Anfang und einen für das Ende, und mit einem x..y-Bereichsausdruck (C#) geschrieben werden kann. Sie können dann mit einem Range indizieren, der ein Segment erzeugt:

var slice = a[i1..i2]; // { 3, 4, 5 }

Weitere Informationen finden Sie im Tutorial Bereiche und Indizes.

Asynchrone Datenströme

Die IAsyncEnumerable<T>-Typ ist eine neue asynchrone Version von IEnumerable<T>. In C# 8.0 können Sie await foreach zur Verarbeitung der IAsyncEnumerable<T>-Elemente nutzen und anschließend yield return zum Erstellen von Elementen verwenden.

Das folgende Beispiel zeigt sowohl die Produktion als auch die Nutzung von asynchronen Datenströmen. Die foreach-Anweisung ist asynchron und verwendet yield return, um einen asynchronen Datenstrom für Anrufer zu erstellen. Dieses Muster (mit yield return) ist das empfohlene Modell zum Erstellen von asynchronen Datenströmen.

async IAsyncEnumerable<int> GetBigResultsAsync()
{
    await foreach (var result in GetResultsAsync())
    {
        if (result > 20) yield return result;
    }
}

Zusätzlich zu await foreach können Sie auch asynchrone Iteratoren erstellen, z.B. einen Iterator, der IAsyncEnumerable/IAsyncEnumerator zurückgibt, in den Sie sowohl await als auch yield einfügen können. Für Objekte, die gelöscht werden müssen, können Sie IAsyncDisposable verwenden, das von verschiedenen BCL-Typen implementiert wird, wie beispielsweise Stream und Timer.

Weitere Informationen finden Sie im Tutorial Generieren und Nutzen asynchroner Datenströme mit C# 8.0 und .NET Core 3.0.

IEEE-Gleitkomma

APIs für Gleitkommazahlen werden aktuell der Revision des Standards IEEE 754-2008 angepasst. Ziel dieser Änderungen ist, alle erforderlichen Operationen verfügbar zu machen und sicherzustellen, dass sie mit dem in der IEEE-Spezifikation beschriebenen Verhalten kompatibel sind. Weitere Informationen über Gleitkommaverbesserungen finden Sie im Blogbeitrag Floating-Point Parsing and Formatting improvements in .NET Core 3.0 (Verbesserungen zu Gleitkommaanalyse und Formatierung in .NET Core 3.0).

Zu den Korrekturen für Analyse und Formatierung zählen:

  • Eingaben mit beliebiger Länge werden richtig analysiert und gerundet.
  • Die negative Null wird richtig analysiert und formatiert.
  • Infinity- und NaN-Werte werden mithilfe einer Überprüfung, bei der nicht zwischen Groß-/Kleinbuchstaben unterschieden wird, richtig analysiert. Außerdem ist, falls erforderlich, optional das vorangestellte +-Zeichen zulässig.

Zu den neuen System.Math-APIs zählen:

  • BitIncrement(Double) und BitDecrement(Double)
    entspricht den IEEE-Operationen nextUp und nextDown. Diese geben jeweils die kleinste Gleitkommazahl zurück, die größer oder kleiner als der Eingabewert ist. Math.BitIncrement(0.0) gibt beispielsweise double.Epsilon zurück.

  • MaxMagnitude(Double, Double) und MinMagnitude(Double, Double)
    entspricht den IEEE-Operationen maxNumMag und minNumMag. Diese geben für zwei Eingabewerte jeweils den Wert zurück, für den ein größerer oder kleinerer Absolutbetrag ermittelt wird. Math.MaxMagnitude(2.0, -3.0) gibt beispielsweise -3.0 zurück.

  • ILogB(Double)
    Entspricht der IEEE-Operation logB, die einen integralen Wert zurückgibt. Der Rückgabewert ist der integrale Wert des Logarithmus zur Basis 2 des Eingabeparameters. Diese Methode entspricht im Wesentlichen floor(log2(x)), jedoch ist der Rundungsfehler minimal.

  • ScaleB(Double, Int32)
    Entspricht der IEEE-Operation scaleB, der ein integraler Wert übergeben wird. Zurückgegeben wird im Wesentlichen x * pow(2, n), jedoch ist der Rundungsfehler minimal.

  • Log2(Double)
    entspricht der IEEE-Operation log2, die den Logarithmus zur Basis 2 zurückgibt. Diese Operation minimiert den Rundungsfehler.

  • FusedMultiplyAdd(Double, Double, Double)
    entspricht der IEEE-Operation fma, die eine Fused-Multiply-Add-Operation durchführt. Dabei wird (x * y) + z als einzelne Operation ausgeführt, wodurch der Rundungsfehler minimiert wird. Ein Beispiel hierfür ist FusedMultiplyAdd(1e308, 2.0, -1e308), diese gibt 1e308 zurück. Die reguläre Operation (1e308 * 2.0) - 1e308 gibt double.PositiveInfinity zurück.

  • CopySign(Double, Double)
    entspricht der IEEE-Operation copySign. Diese gibt den Wert von x mit dem Vorzeichen von y zurück.

Von der .NET-Plattform abhängige systeminterne Funktionen

Mit neuen APIs kann auf bestimmte leistungsorientierte CPU-Anweisungen wie SIMD oder Bit Manipulation Instruction Sets zugegriffen werden. Diese Anweisungen können in bestimmten Szenarios wie der effizienten parallelen Datenverarbeitung zu deutlichen Leistungssteigerungen führen.

Wo möglich, haben die .NET-Bibliotheken begonnen, mithilfe dieser Anweisungen die Leistung zu verbessern.

Weitere Informationen finden Sie unter Von der .NET-Plattform abhängige intrinsische Funktionen.

Verbesserte .NET Core-Versions-APIs

Ab .NET Core 3.0 geben die mit .NET Core gelieferten Versions-APIs jetzt die Informationen zurück, die Sie erwarten. Zum Beispiel:

System.Console.WriteLine($"Environment.Version: {System.Environment.Version}");

// Old result
//   Environment.Version: 4.0.30319.42000
//
// New result
//   Environment.Version: 3.0.0
System.Console.WriteLine($"RuntimeInformation.FrameworkDescription: {System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription}");

// Old result
//   RuntimeInformation.FrameworkDescription: .NET Core 4.6.27415.71
//
// New result (notice the value includes any preview release information)
//   RuntimeInformation.FrameworkDescription: .NET Core 3.0.0-preview4-27615-11

Warnung

Entscheidende Änderung. Dies ist technisch gesehen eine entscheidende Änderung, da das Schema der Versionsverwaltung sich geändert hat.

Schneller integrierter JSON-Support

.NET-Benutzer haben sich weitgehend auf Newtonsoft.Json und andere beliebte JSON-Bibliotheken verlassen, die weiterhin eine gute Wahl sind. Newtonsoft.Json verwendet als Basisdatentyp .NET-Zeichenfolgen, die intern in UTF-16 codiert sind.

Die neue integrierte JSON-Unterstützung ist überaus leistungsfähig mit geringer Zuteilung und funktioniert mit UTF-8-codiertem JSON-Text. Weitere Informationen zum Namespace System.Text.Json und den Typen finden Sie in den folgenden Artikeln:

HTTP/2-Unterstützung

Der System.Net.Http.HttpClient-Typ unterstützt das HTTP/2-Protokoll. Wenn HTTP/2 aktiviert ist, wird die HTTP-Protokollversion über TLS/ALPN ausgehandelt, und HTTP/2 wird bei Auswahl durch den Server verwendet.

Das Standardprotokoll bleibt HTTP/1.1, aber HTTP/2 kann auf zwei verschiedene Arten aktiviert werden. Erstens können Sie die HTTP-Anforderungsnachricht so festlegen, dass HTTP/2 verwendet wird:

var client = new HttpClient() { BaseAddress = new Uri("https://localhost:5001") };

// HTTP/1.1 request
using (var response = await client.GetAsync("/"))
    Console.WriteLine(response.Content);

// HTTP/2 request
using (var request = new HttpRequestMessage(HttpMethod.Get, "/") { Version = new Version(2, 0) })
using (var response = await client.SendAsync(request))
    Console.WriteLine(response.Content);

Zweitens können Sie HttpClient so ändern, dass HTTP/2 standardmäßig verwendet wird:

var client = new HttpClient()
{
    BaseAddress = new Uri("https://localhost:5001"),
    DefaultRequestVersion = new Version(2, 0)
};

// HTTP/2 is default
using (var response = await client.GetAsync("/"))
    Console.WriteLine(response.Content);

Oftmals möchten Sie bei der Entwicklung einer Anwendung eine unverschlüsselte Verbindung verwenden. Wenn Sie wissen, dass der Zielendpunkt HTTP/2 verwendet, können Sie unverschlüsselte Verbindungen für HTTP/2 aktivieren. Sie können sie aktivieren, indem Sie die Umgebungsvariable DOTNET_SYSTEM_NET_HTTP_SOCKETSHTTPHANDLER_HTTP2UNENCRYPTEDSUPPORT auf 1 festlegen oder sie im App-Kontext aktivieren:

AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);

Nächste Schritte