Im Rahmen der .NET Conf 2023 wird Microsoft heute die endgültigen Versionen von .NET 8.0 und C# 12.0 freigeben. Während der Support des im November 2022 erschienenen Vorgängers .NET 7.0 schon im Mai 2024 endet, erhält .NET 8.0 einen Long-Term Support (LTS) von drei Jahren, also bis November 2027. Das vorherige LTS-Release .NET 6.0 unterstützt Microsoft noch bis zum November 2025.
Anzeige
.NET 8.0 wird auf der Downloadseite zur Verfügung gestellt. In den letzten Jahren war dies immer schon einige Stunden vor der offiziellen Verkündung der Fall.
Für .NET 8.0 benötigen Entwickler die Entwicklungsumgebungen Visual Studio 2022 in Version 17.8, die ebenfalls heute Abend als stabile Version erscheinen wird. Auch das kostenfreie Visual Studio Code ist mit aktuellem C#-Add-on möglich.
Entwickelt wurde .NET 8.0 in den letzten 12 Monaten. Seitdem hat Microsoft sieben Preview-Versionen und zwei Release-Candidates veröffentlicht, über die heise Developer jeweils berichtete.
Breaking Changes sind zu beachten
Umsteiger von .NET 6.0 oder .NET 7.0 auf .NET 8.0 müssen nicht nur das Target Framework in der Projektdatei beziehungsweise zentralen Build-Konfigurationsdatei Directory.Build.props auf <TargetFramework>net8.0</TargetFramework>
ändern, sondern auch die zahlreichen Breaking Changes berücksichtigen. Diese dokumentiert Microsoft in Listen:
Dabei hat Microsoft das Darstellungsformat geändert. In der Liste zu .NET 7.0 wurden nur noch in zwei Spalten “Binary compatible” und “Source compatible” unterschieden. In .NET 8.0 gibt es nun drei Kategorien “Binary incompatible”, “Binary incompatible” und “Behavioral change”. .NET 8.0 hat ähnlich viele Breaking Changes wie die Vorgängerversion.
Blazor für alle Fälle
Das Webframework Blazor gibt es seit Version 3.1 des modernen .NET, das damals noch .NET Core hieß. Bisher hatten Entwicklerinnen und Entwickler für Single-Page-Webanwendungen die Qual der Wahl zwischen Blazor Server und Blazor WebAssembly, die sich aufgrund der Vor- und Nachteile beider Architekturen in einigen Praxisfällen wie die Wahl zwischen Pest und Cholera anfühlte. Behelfen konnte man sich, in dem man eine Webanwendung für verschiedene Nutzergruppen oder Standorte in beiden Architekturen anbot.
Heise Developer und die .NET-Experten von www.IT-Visions.de werden dem deutschsprachigen Publikum den fertigen Stand von .NET 8.0 21. November 2023 im Rahmen der Online-Konferenz Better Code .NET 8.0 präsentieren. Bekannte .NET-Experten stellen alle wesentlichen Funktionen anhand von Praxisbeispielen vorstellen:
- Die Neuerungen von .NET 8.0: SDK, Runtime und Basisklassen
- Einfacher lesbarer, stabilerer Code mit C# 12.0
- Alle Neuerungen von ASP.NET Core 8.0 und Blazor 8.0
- Neues beim OR-Mapping mit Entity Framework Core 8.0
- Das hat sich mit Windows Forms 8.0, WPF 8.0 und WinUI 3 verändert
- Cross-Plattform-Entwicklung mit .NET MAUI 8.0
- Ausblick auf .NET 9.0
.NET 8.0 erlaubt nun, beide Architekturen in einer einzigen Webanwendung zu vereinen. Der neue Rendering-Modus “Auto” rendert eine Webanwendung zunächst per Blazor Server mit Interaktivität per Websocket-Verbindung (siehe .NET 8.0 Preview 7 bringt Auto-Modus für Blazor). Nachdem im Hintergrund die umfangreichen Dateien für Blazor WebAssembly nachgeladen wurden, kann die Webanwendung zum rein lokalen Rendering im Browser übergehen, und die Websocket-Verbindung wird wieder beendet. Der Autor hat dazu die Beispielanwendung MiracleList erstellt, für deren Zugang eine kostenlose Registrierung erforderlich ist.
Außerdem ermöglicht Blazor 8.0 jetzt erstmals ein reines serverseitiges Rendern einer Multi-Page-Webanwendung. Microsoft nannte dieses Architekturmodell in der Preview-Phase (siehe Vorschau auf .NET 8.0: SPA-Inseln beim Server-side Rendering) noch “Blazor Server-Side-Rendering (SSR)”, hat sich aber in der endgültigen Version entschlossen, SSR für “Static-Server-Rendering” stehen zu lassen – mit dem Ziel, eine klarere Abgrenzung zu Blazor Server zu schaffen. Aber auch die neue Wortwahl kann zu Verwirrungen führen, weil einige Webframeworks unter dem Begriff “Static-Side-Generation” ein Rendering zur Entwicklungszeit anbieten. Blazor SSR rendert aber nicht zur Entwicklungszeit, sondern zur Laufzeit.
Die Architektur von Blazor SSR entspricht grundsätzlich dem, was in .NET bisher mit ASP.NET Core Model-View-Controller (MVC) und ASP.NET Core Razor Pages angeboten wurde. Allerdings kann Blazor SSR mit zusätzlichen Features punkten:
- Blazor SSR bietet im Gegensatz zu MVC/Razor Pages ein echtes Komponentenmodell, bei dem sich Komponenten leicht ineinander einbetten lassen.
- Die Razor-Template-Syntax in Blazor SSR bietet mehr Funktionen als die Razor Views und Razor Pages.
- Asynchron gerenderte Inhalte lassen sich in der HTTP-Antwort nachsenden (Streaming).
- Seitenteile können einzeln gesendet werden (Enhanced Navigation).
- In einer statisch gerenderten Site können Entwicklerinnen und Entwickler SPA-Inseln (einzelne Seiten oder auch Seitenteile) einbetten, die mit Blazor Server, Blazor WebAssembly oder im Auto-Modus laufen.
Während Blazor SSR im Kern ohne JavaScript läuft, erfordern die letzten drei Punkte die Einbindung der von Microsoft in .NET mitgelieferten JavaScript-Datei blazor.web.js.
Man kann sicherlich sagen: Das Grab für MVC und Razor Pages ist durch die Einführung von Blazor SSR schon ausgehoben, auch wenn Microsoft die Beerdigung der beiden älteren Modelle bisher nicht verkündet hat.
Ein Praxisfall für Blazor SSR mit SPA-Inseln ist eine öffentliche Firmenwebsite, die in Hinblick auf Search Engine Optimization (SEO) nicht als SPA realisiert ist. Einzelne Teile der Website implementiert man dann aber als SPA-Inseln, beispielsweise das Kontaktformular, die Standortsuche und den Produktkonfigurator, um Benutzerinnen und Benutzern in Formularen eine bessere User Experience (UX) zu geben.
Abbildung 1 zeigt die Architekturen ASP.NET Core MVC, ASP.NET Core Razor Pages, Blazor SSR ohne Streaming und Blazor SSR mit Streaming sowie Blazor Server und Blazor WebAssembly im Vergleich. Von dem bei der Erstankündigung am 24. Januar 2023 auf YouTube verkündeten Oberbegriff “Blazor United” für die neuen Funktionen ist Microsoft wieder abgekommen.
Blazor Web Apps
Zudem hat Microsoft die Projektvorlagen für Blazor aufgeräumt (siehe Abbildung 2 und .NET 8.0: Zweite Preview beschleunigt WebAssembly-Anwendungen): Fast alle Möglichkeiten von Blazor SSR, Blazor WebAssembly und Blazor Server findet man in der Vorlage “Blazor Web App”. Lediglich für Blazor-WebAssembly-Anwendungen, die unabhängig von einem ASP.NET Core-basierten Webserver laufen, gibt es die getrennte Vorlage “Blazor WebAssembly Standalone App” sowie eine Vorlage für hybride Blazor-Anwendungen auf Basis von .NET MAUI.
In der RTM-Version von Blazor 8.0 wird Microsoft noch einige Änderungen vornehmen und Schwächen beheben. Dazu gehört, dass in der Projektvorlage die neue Direktive @rendermode
zum Einsatz kommt. Zum Beispiel findet sich statt
@attribute [RenderModeInteractiveServer]
dort nun
@rendermode InteractiveServer
Das in Release Candidate 2 für einige Fehlerkorrekturen erforderliche NuGet-Paket Microsoft.Net.Compilers.Razor.Toolset kann in Projekten auf Basis der RTM-Version entfallen.
C# 12.0 mit Syntaxvereinfachungen
In C# 12.0 gibt es nur ungefähr halb so viele Syntax-Neuerungen wie im Vorgänger C# 11.0. Die drei bedeutenden Neuerungen sind:
- Vereinfachte Initialisierung und Zuweisung für Mengen,
- Primärkonstruktoren und
- optionale Lambda-Parameter.
In C# 12.0 können Entwicklerinnen und Entwickler Mengen nun in der gleichen Syntax mit eckigen Klammern wie in JavaScript/TypeScript zuweisen, beispielsweise
List<int> d = [1,2,3];
Span<int> b = [1,2,3];
string[] sites1, sites2, sites3 = ["www.dotnetframework.de", "www.dotnet8.de"];
sites1 = ["www.dotnet-doktor.de", "dotnet-lexikon.de"];
sites2 = [];
Der Spread-Operator erzeugt ein Array aus den Elementen anderer Arrays:
string[] allSitesAsArray =
[.. sites1, .. sites2, "www.IT-Visions.de", .. sites3];
Primärkonstruktoren für Klassen gab es schon in C# 6.0 als Prototyp, sie kamen im Jahr 2015 allerdings nicht in das fertige Produkt. Nur Record-Typen, die es seit C# 9.0 gibt, haben bisher Primärkonstruktoren. In C# 12.0 ist die Syntax mit Parametern hinter dem Klassennamen auch für Klassen erlaubt. Anders als bei Record-Typen erzeugen Primärkonstruktoren bei Klassen jedoch keine öffentlichen Properties. Um öffentlich auf die im Primärkonstruktor übergebenen Daten zugreifen zu können, muss man die Konstruktorparameter für Zuweisungen verwenden:
/// <summary>
/// Klasse mit Primärkonstruktor
/// </summary>
public class Person(Guid personGuid, string name)
public Guid PersonGuid get; set; = personGuid;
public string Name get; set; = name;
public Person() : this(Guid.Empty, "")
public override string ToString()
return $"Person personGuid: Name";
Lambdas haben in den letzten Jahren an immer mehr Stellen in der .NET-Programmierung Methoden ersetzt. Allerdings erlaubten Lambdas bisher keine optionalen Parameter. Das hat sich in C# 12.0 geändert. Anstelle folgender Funktion mit optionalem Parameter z
public decimal Calc(decimal x, decimal y, decimal z = 1)
return (x + y) * z;
ist in C# 12.0 nun folgender Lambda-Ausdruck erlaubt:
var calc = (decimal x, decimal y, decimal z = 1) => (x + y) * z;
AOT für weitere Anwendungsarten
Der letztes Jahr in .NET 7.0 eingeführte, aber dort noch auf Konsolenanwendungen beschränkte Ahead-of-Timer-Compiler “Native AOT” kann in .NET 8.0 nun auch Worker Services, gRPC-Dienste und ASP.NET Core WebAPIs (aber nur, wenn diese als Minimal-APIs angelegt sind) übersetzen. Datenbankzugriffe sind nur per ADO.NET möglich; Entity Framework Core funktioniert nicht mit dem AOT-Compiler.
Erweiterungen der Basisklassenbibliothek
Wie in jeder der letzten .NET-Versionen hat Microsoft auch diesmal die Basisklassenbibliothek erweitert. Dazu gehören:
- Neue Validierungsannotationen im Namensraum
System.ComponentModel.DataAnnotations
, darunter[AllowedValues]
,[DeniedValues]
und[Base64String]
sowie Erweiterungen bei [Range] und [Length]. - Eingefrorene Objektmengen:
FrozenSet<T>
undFrozenDictionary<T, T>
im neuen NamensraumSystem.Collections.Frozen
. - Neue Zufallsfunktionen in der Klasse
System.Random
: Zufallsreihenfolge mitRandom.Shared.Shuffle()
und Zufallauswahl viaRandom.Shared.GetItems()
. - Neue Methoden zum Auslösen von Fehlern in Methodenparametern wie
ArgumentOutOfRangeException.ThrowIfZero()
,ArgumentOutOfRangeException.ThrowIfNegative()
,ArgumentOutOfRangeException.ThrowIfNegativeOrZero()
undArgumentOutOfRangeException.ThrowIfGreaterThan()
. - Privilegien-Abfrage mit
System.Environment.IsPrivilegedProcess
. - Dependency Injection mit Schlüsseln:
services.AddKeyedSingleton<T1, T2>("Name")
undserviceProvider.GetKeyedService<T1>("Name")
. - Zeitabstraktion mit der neuen Klasse
System.TimeProvider
. Parse()
undTryParse()
in der KlasseSystem.Net.IPNetwork
.- Razor-Template-Rendering außerhalb von Blazor in beliebigen .NET-Anwendungen mit der Klasse
Microsoft.AspNetCore.Components.Web.HtmlRenderer
im NuGet-PaketMicrosoft.AspNetCore.Components.Web
. - Source-Generator für das Component Object Model (COM):
[GeneratedComInterface]
und[GeneratedComClass]
im NamensraumSystem.Runtime.InteropServices.Marshalling
. - Einige neue Code-Analyzer, die Verbesserungen vorschlagen, beispielsweise hinsichtlich des Einsatzes von
Equals()
statt Case-Insensitive-Vergleichen mitToLower()
/ToUpper()
,StartsWith()
stattIndexOf() == 0
undLength
/Count
stattAny()
.
Ein kostenfreies Cheat Sheet mit den wichtigsten Neuerungen in C# 12.0 und der .NET-Basisklassenbibliothek findet sich auf der Website des Autors.
Neues für den Objekt-Relationalen Mapper
Zudem gibt es umfangreiche Verbesserungen beim Objekt-Relationalen Mapper Entity Framework Core in Version 8.0. Dazu gehören:
- Mapping für die in .NET 6.0 eingeführten
System.DateOnly
undSystem.TimeOnly
auch im Microsoft SQL Server, - Datentypen
long
undulong
für Timestamp-Spalten als Alternative zu Byte-Arrays, - Mapping von Arrays und Listen elementarer Typen auf JSON-Zeichenketten,
- JSON-Mapping von Klassen mit
ToJson()
auch für SQLite-Datenbanken, - Table Splitting mit Complex Types als Alternative zu den bisher verfügbaren Owned Types via Annotation
[ComplexType]
oder Fluent-API per MethodenaufrufComplexProperty()
, - hierarchische Daten im SQL Server mit dem SQL Server-Spaltentyp “hierarchyid” im NuGet-Paket
Microsoft.EntityFrameworkCore.SqlServer.HierarchyId
, - Mapping von SQL-Abfragen auf beliebige, nicht in der Kontextklasse registrierte Typen mit
ctx.Database.SqlQuery()
undctx.Database.SqlQueryRaw()
, - Das Lazy Loading funktioniert auch bei No-Tracking-Abfragen.
- Abschalten des Lazy Loading für einzelne Beziehungen mit
EnableLazyLoading(false)
, - Asynchrones explizites Nachladen mit
LoadAsync()
, - Automatisch begrenzte Länge der Diskriminatorspalten bei Table-per-Hierarchy-Mapping,
- Bessere SQL-Übersetzung des LINQ-Operators
Contains()
, - Übersichtlichere SQL-Generierung aus LINQ-Abfragen ohne überflüssige Klammern.
- Abfrage der Objekte im lokalen Zwischenspeicher mit
Local.FindEntry()
undLocal.GetEntries()
. - Statusabfrage, ob es Änderungen im Objektmodell gibt, für die es noch keine Datenbankschema-Migration gibt: via Kommandozeile
dotnet ef migrations has-pending-model-changes
. - Festlegen des von Entity Framework Core intern verwendeten Wächterwerts, um festzustellen, dass ein Wert nicht der im Datenbankmanagementsystem hinterlegte Standardwert ist:
HasSentinel()
. - Die in Entity Framework Core 7.0 eingeführten Methoden
ExecuteUpdate()
undExecuteDelete()
funktionieren in Version 8.0 auch in Fällen, bei denen mehrere Entitätsklassen auf eine einzige Tabelle (z.B. bei der TPH-Vererbung) abgebildet sind.
Entity Framework Core 8.0 läuft nur auf .NET 8.0; bis Preview 6 waren auch .NET 6.0 und 7.0 als Basis möglich.
Weitere Neuerungen findet man in ASP.NET Core innerhalb und außerhalb von Blazor, im JSON-Serializer sowie auch in den Desktop-UI-Frameworks Windows Forms und WPF.
(rme)