.NET 9.0 Preview 2: Kritik an Microsoft wegen der Kommunikation
Die unübersichtliche Darstellung der Neuerungen in .NET 9.0 Preview 2 gefällt vielen nicht. Zudem ist die Anzahl der neuen Funktionen in Preview 2 überschaubar.
- Dr. Holger Schwichtenberg
In den letzten Jahren gab es zu jeder Vorschauversion des modernen .NET mehrere Blogeinträge im Microsoft .NET Blog. Das galt bis einschließlich November 2023, dem Erscheinungstermin von .NET 8.0.
Zu .NET 9.0 Preview 1 gab es nur noch einen Blogeintrag über die "Vision zu .NET 9" und die Ankündigung von .NET Program Manager Rich Lander, das Erscheinen zukünftiger Vorschauversionen über einen Diskussionsbereich auf GitHub anzukündigen und nur noch über die Release Notes sowie "What's New"-Dokumente auf Microsoft Learn zu dokumentieren.
Lesen Sie auch
.NET 9.0: Erste kleine Preview und schwammige Visionen
In den Release Notes zu .NET 9.0 Preview 2 sind die Neuerungen über mehrere Dokumente verstreut und meist nur sehr knapp erwähnt. In den "What's New"-Dokumenten zu .NET 9.0, ASP.NET Core 9.0, Entity Framework Core 9.0 und .NET MAUI sind die Neuerungen zwar größtenteils ausführlicher beschrieben, aber in einem einzigen Dokument zu Preview 1 und Preview 2 vermischt. Dadurch ist nicht direkt erkennbar, was in welcher Vorschauversion hinzugekommen ist. Um die Unterschiede zu erkennen, muss man die Git-History der Dokumentationsseite aufrufen und sich durch die Änderungen durcharbeiten.
Die Kommentare auf GitHub zeigen, dass diese neue Kommunikation den Kundinnen und Kunden gar nicht gefällt: "confusing", "badly done" und "before it was even out was so much better". Auch ein ketzerischer Kommentar wie "so, is .net dead?" fehlt nicht. Mitarbeiter von Microsoft haben inzwischen reagiert. Sie kündigen an, die Darstellung zu überdenken: "I will make notes to ask our product and documentation teams to provide clear diffs" schreibt Jon Douglas in einem Kommentar.
Verbesserungen im .NET SDK
Das Kommandozeilenwerkzeug dotnet test
konnte bisher schon automatisierte Tests für ein Projekt mit mehreren .NET-Versionen nacheinander ausführen. Neu in .NET 9.0 Preview 2 ist, dass dies parallel passiert.
Zudem verwendet dotnet test
den in .NET 8.0 eingeführten, übersichtlicheren Terminal Logger, was sich insbesondere positiv auf die Darstellung der Testergebnisse während und nach der Testausführung auswirkt.
Bei .NET-SDK-basierten Werkzeugen haben Entwicklerinnen und Entwickler nun die Möglichkeit, mit der Option --allow-roll-forward
das Werkzeug auf einer neueren .NET-Hauptversion laufen zu lassen, wenn die .NET-Laufzeitumgebung, für die das Werkzeug kompiliert wurde, nicht verfügbar ist. Diese neue Option kann sowohl bei dotnet tool install
als auch dotnet tool run
verwendet werden. Es gibt aufgrund der Breaking Changes zwischen .NET-Hauptversionen keine Garantie, dass das Werkzeug auf einer neueren .NET-Laufzeitumgebung funktioniert.
Optimierungen in Runtime und Entity Framework Core
In .NET 9.0 Preview 2 hat Microsoft drei Optimierungen in den Just-in-Time-Compiler für 64-Bit-Systeme eingebaut. Dazu gehören die verbesserte Übersetzung von Schleifen, das Inlining beim Ahead-of-Time-Compiler und die dynamische Profile-Guided Optimization (PGO). Diese Verbesserungen sind im "Whats New"-Dokument dynamic profile-guided optimization (PGO) beschrieben.
Auch bei Entity Framework Core 9.0 Preview 2 gibt es Optimierungen. Bei der Erstellung von Autowerten mit Sequenzen lässt sich neuerdings Caching via UseCache()
und UseNoCache()
konfigurieren:
modelBuilder.HasSequence<int>("NameDerSequence")
.HasMin(10).HasMax(255000)
.IsCyclic()
.StartsAt(11).IncrementsBy(2)
.UseCache(3);
Bei Schlüssel- und Indexspalten können jetzt für den Microsoft SQL Server Angaben zum Füllfaktor gemacht werden. Er bestimmt den Prozentsatz des Platzes auf einer Seite in der Datenbankdatei, der mit Daten gefüllt werden soll, wobei der Rest auf jeder Seite als freier Platz für zukünftiges Wachstum reserviert wird. Der Füllfaktor kann nun in Entity Framework Core 9.0 via HasFillFactor()
gesetzt werden für einfache und zusammengesetzte Schlüsselspalten und Indexe:
modelBuilder.Entity<User>()
.HasKey(e => e.Id)
.HasFillFactor(80);
modelBuilder.Entity<User>()
.HasAlternateKey(e => new { e.Region, e.Ssn })
.HasFillFactor(80);
modelBuilder.Entity<User>()
.HasIndex(e => new { e.Name })
.HasFillFactor(80);
modelBuilder.Entity<User>()
.HasIndex(e => new { e.Region, e.Tag })
.HasFillFactor(80);
Bei der Übersetzung von LINQ zu SQL fasst Entity Framework Core 9.0 nun die SQL-Befehle von verschachtelten LINQ-Abfragen zusammen. Während in Version 8.0 des objektrelationalen Mappers aus diesen beiden verschachtelten LINQ-Befehlen
var dotnetPosts = context
.Posts
.Where(p => p.Title.Contains(".NET"));
var results = dotnetPosts
.Where(p => p.Id > 2)
.Select(p => new { Post = p,
TotalCount = dotnetPosts.Count() })
.Skip(2).Take(10)
.ToArray();
zwei SQL-Befehle zum Datenbankmanagementsystem gesendet wurden
SELECT COUNT(*)
FROM [Posts] AS [p]
WHERE [p].[Title] LIKE N'%.NET%'
SELECT [p].[Id], [p].[Archived], [p].[AuthorId],
[p].[BlogId], [p].[Content],
[p].[Discriminator], [p].[PublishedOn],
[p].[Title], [p].[PromoText], [p].[Metadata]
FROM [Posts] AS [p]
WHERE [p].[Title] LIKE N'%.NET%' AND [p].[Id] > 2
ORDER BY (SELECT 1)
OFFSET @__p_1 ROWS FETCH NEXT @__p_2 ROWS ONLY
entsteht nun in Version 9.0 nur noch ein SQL-Befehl:
SELECT [p].[Id], [p].[Archived], [p].[AuthorId],
[p].[BlogId], [p].[Content], [p].[Discriminator],
[p].[PublishedOn], [p].[Title],
[p].[PromoText], [p].[Metadata], (
SELECT COUNT(*)
FROM [Posts] AS [p0]
WHERE [p0].[Title] LIKE N'%.NET%')
FROM [Posts] AS [p]
WHERE [p].[Title] LIKE N'%.NET%' AND [p].[Id] > 2
ORDER BY (SELECT 1)
OFFSET @__p_0 ROWS FETCH NEXT @__p_1 ROWS ONLY
Analog zur bereits in Entity Framework Core 2.0 eingeführten Materialisierungsmethode ToHashSet()
gibt es nun ein asynchrones Pendant: ToHashSetAsync()
.
Die Konventionen für die Modellerstellung hat Microsoft verschlankt, wie ein Beispiel in der Dokumentation zeigt.
Die Entity-Framework-Core-Kommandozeilenwerkzeuge sollen nun seltener ein Neukompilieren des Projekts erfordern. Ein Community-Mitglied hat dazu einen Beitrag geleistet. Auch die Verbesserungen für die Sequenzen und den Füllfaktor sowie die Erweiterung von ToHashSetAsync()
kamen von Personen, die nicht bei Microsoft angestellt sind.
In der "What's New"-Dokumentation findet man zudem einen Text zu einer Verbesserung bei der Hierarchy-ID: Die in Entity Framework Core 8.0 eingeführte Hierarchy-ID soll man nicht nur wie bisher als Zeichenkette wie "/4/1/3/1/2/"
, sondern auch typsicherer auf Basis einer anderen Hierarchy-ID erstellen können:
var daisy =
await context.Halflings.SingleAsync(e => e.Name == "Daisy");
va r child1 =
new Halfling(HierarchyId.Parse(daisy.PathFromPatriarch, 1), "Toast");
var child2 =
new Halfling(HierarchyId.Parse(daisy.PathFromPatriarch, 2), "Wills");
var child1b =
new Halfling(HierarchyId.Parse(daisy.PathFromPatriarch, 1, 5), "Toast");
Allerdings zeigte ein Schnelltest, dass dies in Entity Framework Core 9.0 Preview 2 noch nicht funktioniert. Vermutlich ist dafür die kommende dritte Vorschauversion notwendig.
Verbesserungen für Blazor und Authentifizierung
Im Webframework Blazor ist in Razor Components eine Dependency Injection nun auch per Konstruktor möglich:
using Microsoft.AspNetCore.Components;
public partial class ConstructorInjection(NavigationManager navigationManager)
{
private void NavigateToCounter() => navigationManager.NavigateTo("/counter");
}
Bisher konnte man Dienste nur per @inject
in der Template-Datei beziehungsweise per Annotation [Inject]
auf einer Eigenschaft im Code injizieren.
Beim Interactive Server-Side Rendering (alias Blazor Server) ist nun die Komprimierung der Websockets-Daten im Standard aktiv. Entwicklerinnen und Entwickler können dies aber bei Bedarf durch Setzen von DisableWebSocketCompression = true
im Parameterobjekt von AddInteractiveServerRenderMode()
deaktivieren:
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode(o => o.DisableWebSocketCompression = true);
Die Content Security Policy (CSP) setzt Microsoft nun im Standard auf frame-ancestor: 'self'
. Dies kann man via ContentSecurityFrameAncestorsPolicy
ändern:
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode(o => o.ContentSecurityFrameAncestorsPolicy="'none'");
Für OAuth and OIDC kann man nun die Parameter einfacher anpassen:
builder.Services.AddAuthentication().AddOpenIdConnect(options =>
{
options.AdditionalAuthorizationParameters.Add("prompt", "login");
options.AdditionalAuthorizationParameters.Add("audience", "https://api.example.com");
});
Kaum Bewegung bei den anderen GUIs und den Basisklassen
Bei .NET MAUI gibt es bisher eine Vielzahl von Fehlerbehebungen und kleinerer Verbesserungen wie animierte GIFs auf iOS.
Informationen zu Verbesserungen bei Windows Forms oder der Windows Presentation Foundation (WPF) ließen sich in den Release Notes nicht finden. Immerhin gab es aber im Februar ein Bekenntnis von Microsoft, weiter am Designer für Windows Forms in Visual Studio zu arbeiten.
In den Release Notes sind auch keine Neuerungen in der .NET-Basisklassenbibliothek erwähnt, mit Ausnahme der Verbesserungen, die bereits in Preview 1 erschienen sind. In den Kommentaren findet sich dann aber noch ein Hinweis auf die neue Konfigurationseinstellung AllowOutOfOrderMetadataProperties
in System.Text.Json
, die aber in den Release Notes und der Dokumentation fehlt.
Kostenfreier Download
Die .NET 9.0 Preview 2 gibt es zum kostenfreien Download. Die mitgelieferte C#-Version ist immer noch (wie bei .NET 8.0) 12.0. Die Versionsnummern der im SDK mitgelieferten Runtimes zeigt Abbildung 3.
Das Erstellen von .NET-9.0-Projekten funktioniert nicht mit der aktuellen stabilen Visual-Studio-Version 2022 17.9, sondern erfordert eine Vorschau von Version 17.10. Alternativ dazu kann man .NET-9.0-Projekte an der Kommandozeile via dotnet new
erstellen.
(rme)