Microsoft veröffentlicht .NET 9.0 Preview 4

Auf der Microsoft Build 2024 ist die nächste Preview für .NET 9.0 mit Verbesserungen für den objektrelationalen Mapper, ASP.NET Core und Blazor erschienen.

In Pocket speichern vorlesen Druckansicht 1 Kommentar lesen

(Bild: Pincasso/Shutterstock.com)

Lesezeit: 8 Min.
Von
  • Dr. Holger Schwichtenberg
Inhaltsverzeichnis

Microsoft hat .NET 9.0 Preview 4 auf seiner Entwicklerkonferenz Build 2024 veröffentlicht. .NET war (wie in den vergangenen Jahren) kein Thema in der Keynote der Konferenz. Dort ging es zwei Stunden lang nur um das Thema KI. Man findet allerdings im Build Session Scheduler unter dem Suchbegriff ".NET" sowohl einige Live-Sessions, etwa am Donnerstag, 17.30 Uhr MESZ zu C# 13.0 und dem zu Beginn des Monats Mai erstmals in einer stabilen Version erschienenen MongoDB-Datenbanktreiber für Entity Framework Core als auch zuvor aufgenommene Vorträge zu ASP.NET Core 9.0 und Blazor 9.0 sowie Entity Framework Core 9.0.

In der vierten Vorschauversion des objektrelationalen Mappers Entity Framework Core 9.0 gibt es mehrere interessante Neuerungen. Die wichtigste ist die Verwendung von schreibgeschützten Objektmengen als Typ für einzelne Properties. In Entity Framework Core 8.0 hatte Microsoft die Möglichkeit eingeführt, Arrays und typisierte Listen wie List<int> für einzelne Properties zu verwenden. Während PostgreSQL einen eigenen Mengentyp für diese Fälle bereitstellt, erfolgt in anderen Datenbankmanagementsystemen eine Abbildung auf JSON-Arrays in einer Textspalte (zum Beispiel nvarchar(MAX) in Microsoft SQL Server und TEXT in SQLite).

Nun erweitert Microsoft diese Mengenabbildungen auf die schreibgeschützten .NET-Typen IReadOnlyList, IReadOnlyCollection und ReadOnlyCollection, siehe Listing 1.

public class DataTypeTest
{
 public Int32 ID { get; set; }
…
 #region Array-Typ-Mapping --> Neu in EFCore 8.0 (zuvor nur für PostgreSQL!)
 [Comment("C#: byte[]")]
 public byte[] ByteArray { get; set; }
 
 [Comment("C#: short[]")]
 public short[] ShortArray { get; set; }
 
 [Comment("C#: int[]")]
 public int[] IntArray { get; set; }
 
 [Comment("C#: long[]")]
 public long[] LongArray { get; set; }
 
 //[Comment("C#: byte[]")] --> Immer noch nicht möglich in EFC 9.0 :-(
 //public Int128[] Int128Array { get; set; }
 
 [Comment("C#: string[]")]
 public string[] StringArray { get; set; }
 
 [Comment("C#: DateTime[]")]
 public DateTime[] DateTimeArray { get; set; }
 
 [Comment("C#: bool[]")]
 public bool[] BoolArray { get; set; }
 
 [Comment("C#: Guid[]")]
 public Guid[] GuidArray { get; set; }
 
 [Comment("C#: ABC[]")]
 public ABC[] EnumArray { get; set; }
 #endregion
 
 #region Listen
 [Comment("C#: List<int>")]
 public List<int> IntList { get; set; }
 
 [Comment("C#: List<Guid>")]
 public List<Guid> GuidList { get; set; }
 #endregion
 
 #region ReadOnly-Listen (Neu in EFCore 9.0)
 [Comment("C#: ReadOnlyCollection<int>")]
 public ReadOnlyCollection<int> ReadOnlyCollection { get; set; }
 
 [Comment("C#: IReadOnlyCollection<int>")]
 public IReadOnlyCollection<int> IReadOnlyCollection { get; set; } = new List<int>();
 
 [Comment("C#: IReadOnlyList<int>")]
 public IReadOnlyList<int> IReadOnlyList { get; set; } = new List<int>();
 
 #endregion
…
}

Listing 1: IReadOnlyList, IReadOnlyCollection und ReadOnlyCollection beim OR-Mapping

Die Verwendung der schreibgeschützten Mengentypen in LINQ-Abfragen ist möglich. Entity Framework Core 9.0 übersetzt zum Beispiel diese LINQ-Befehlsfolge:

 var resultSet = ctx.DataTypeTest
   .Where(x => x.ReadOnlyCollection.Any(x => x >= 42))
   .Select(x => new DataTypeTest() { ID = x.ID, ReadOnlyCollection = x.ReadOnlyCollection })
   .ToList();

in diese SQL-Abfrage:

SELECT "d"."ID", "d"."ReadOnlyCollection"
      FROM "DataTypeTest" AS "d"
      WHERE EXISTS (
          SELECT 1
          FROM json_each("d"."ReadOnlyCollection") AS "r"
          WHERE "r"."value" >= 42)

Zudem ist in Entity Framework Core seit Version 9.0 Preview 4 eine SQL-Übersetzung von LINQ-Abfragen mit Gruppierungen über komplexe Typen möglich, zum Beispiel:

var q2 = ctx.DataTypeTest
.GroupBy(b => b.KomplexerTyp)
.Select(g => new { g.Key, Count = g.Count() });

Hieraus entsteht diese SQL-Abfrage für den Fall, dass KomplexerTyp zwei Datenmitglieder mit Namen Feld1 und Feld2 besitzt:

SELECT "d"."KomplexerTyp_Feld1", "d"."KomplexerTyp_Feld2", COUNT(*) AS "Count"
FROM "DataTypeTest" AS "d"
GROUP BY "d"."KomplexerTyp_Feld1", "d"."KomplexerTyp_Feld2"
Online-Konferenz zu .NET 9.0 am 19. November

(Bild: Dmytro Vikarchuk/Shutterstock)

In der Online-Konferenz betterCode() .NET 9.0 am 19. November 2024 von iX und dpunkt.verlag werden .NET-Experten von www.IT-Visions.de den fertigen Stand von .NET 9.0 anhand von Praxisbeispielen präsentieren. Dazu zählen die Neuerungen bezüglich des .NET 9.0 SDK, C# 13.0, ASP.NET Core 9.0, Blazor 9.0, OR-Mapping mit Entity Framework Core 9.0, Windows Forms 9.0, WPF 9.0, WinUI, Cross-Plattform-Entwicklung mit .NET MAUI 9.0 und ein Ausblick auf .NET 10.0.

Der Ticketverkauf ist bereits gestartet: Vor Bekanntgabe des Programms sind vergünstigte Blind-Bird-Tickets erhältlich.

Weitere Verbesserungen finden sich im Entity-Framework-Core-Datenbanktreiber für Azure Cosmos DB, der nun auch die rollenbasierte Zugriffskontrolle (RBAC) unterstützt. Der Cosmos-DB-Provider hat bereits seit Entity Framework Core 6.0 primitive Sammlungen in begrenzter Form unterstützt.

Version 9.0 verbessert diese Unterstützung, indem sie die Metadaten und API-Oberflächen für primitive Sammlungen in Dokumentdatenbanken mit denen in relationalen Datenbanken konsolidiert. Dadurch lassen sich primitive Sammlungen explizit mit der Modellierungs-API abbilden, was die Konfiguration von Facetten des Elementtyps ermöglicht. Zum Beispiel ist es nun möglich, eine Liste von erforderlichen (Nicht-Null-)Zeichenfolgen wie folgt abzubilden:

modelBuilder.Entity<Book>()
    .PrimitiveCollection(e => e.Quotes)
    .ElementType(b => b.IsRequired());

Zudem wirft der Entity-Framework-Core-Datenbanktreiber für Azure Cosmos DB nun einen Laufzeitfehler aus, wenn Entwicklerinnen und Entwickler synchrone Zugriffe (etwa mit ToList()) versuchen. Der Treiber unterstützt intern jedoch keine synchronen Zugriffe. Bisher waren sie dennoch möglich: Sie wurden intern asynchron ausgeführt und dann wurde bis zum Ausführungsende blockiert. Das konnte zu Deadlocks führen. In Version 9.0 gibt es in diesem Falle nun im Standard einen Laufzeitfehler. Derzeit kann man das alte Verhalten noch wiederherstellen mit:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    => optionsBuilder.ConfigureWarnings(b => b.Ignore(CosmosEventId.SyncNotSupported));

Microsoft hat aber angekündigt, dass man in Version 11.0 von Entity Framework Core, die 2026 erscheinen wird, synchrone Aufrufe im Treiber für Azure Cosmos DB komplett verbieten will. Spätestens dann muss man asynchrone Materialisierungsoperationen wie ToListAsync() verwenden.

Für die Generierung einer OpenAPI-Spezifikation zu REST-APIs verwendet Microsoft bisher das externe NuGet-Paket Swashbuckle.AspNetCore. Es war jedoch bis vor Kurzem nicht kompatibel mit dem Native-AOT-Compiler (siehe GitHub Issue und Pull Request), den Microsoft in .NET 8.0 auf ASP.NET-Core-basierte WebAPIs ausgedehnt hat.

Nach vielen Beschwerden von Entwicklern hat Microsoft nun begonnen, die Generierung eines JSON-Dokuments mit OpenAPI-Spezifikation in das Paket Microsoft.AspNetCore.OpenApi ab Version 9.0 Preview 4 einzubauen. Zwar verwenden die ASP.NET-Core-WebAPI-Projektvorlagen weiterhin nicht dieses Paket, aber Entwicklerinnen und Entwickler können die Projekte leicht umbauen, indem sie die Aufrufe

builder.Services.AddOpenApi();

und

app.MapOpenApi();

in der Programmstartdatei einfügen und dann das OAS-JSON-Dokument unter der relativen URL openapi/v1.json abrufen. In einem Schnelltest funktioniert dies aber noch nicht mit dem Native-AOT-Compiler (Fehler: "InvalidOperationException: Reflection-based serialization has been disabled for this application"), obwohl die Dokumentation zumindest in einem Satz andeutet "Compatible with native AoT". Oft kommuniziert Microsoft aber schon in der Dokumentation Ziele für die kommenden Releases, die in den aktuellen Preview-Versionen noch gar nicht realisiert sind. Zudem erzeugt das neue Paket (anders als Swashbuckle.AspNetCore) bisher nur ein JSON-Dokument, aber keine HTML-basierte Hilfe- und Testseite für die WebAPIs.

Außerdem hat Microsoft in ASP.NET Core WebAPI 9.0 Preview 4 für WebAPIs und andere ASP.NET-Core-basierte Anwendungen die Entwickler-Informationsseite bei Laufzeitfehlern durch größere Schrift, verbesserte Abstände und Umbrüche optimiert. Ein Beispiel sieht man in einer Animation auf GitHub.

Das ASP.NET Core Module (ANCM) im Webserver Internet Information Services (IIS) besitzt nun eine neue Einstellung shutdownDelay. Mit dieser legt man in Millisekunden fest, wie lange eine laufende Anwendung beim Recycling eines Anwendungsprozesses noch weiterlaufen soll. Die Überlappung des alten und des neuen Prozesses stellt sicher, dass eine Anwendung auch beim Recycling (etwa bei Codeaktualisierung) kontinuierlich erreichbar ist.

Im Standard hat Microsoft diese Überlappung bisher auf eine Sekunde festgelegt, was aber in einigen Fällen (langsames System oder hohe CPU-Last) nicht ausreichte. Nun können Betreiber einer Anwendung die Überlappung selbst per Einstellung in der Webserverkonfigurationsdatei Web.config steuern:

<aspNetCore processPath="dotnet" arguments="myapp.dll" stdoutLogEnabled="false" stdoutLogFile=".logsstdout">
  <handlerSettings>
    <!--
    Milliseconds to delay shutdown of the old app app instance while the new instance starts.
    Note: This doesn't delay the handling of incoming requests.
    -->
    <handlerSetting name="shutdownDelay" value="5000" />
  </handlerSettings>
</aspNetCore>

Außerdem gibt es einen neuen hybriden Cache, der die bestehenden Implementierungen Distributed Cache und Memory Cache verbessert. Details erklärt Microsoft in den Release Notes.

In Blazor gibt es seit Version 8.0 neben Blazor Server (alias Interactive Server-Side Rendering) und Blazor WebAssembly (alias Client-Side Rendering) auch einen beide Verfahren kombinierenden Auto-Render Mode und statisches Server-Side Rendering für klassische Multi-Page Web Applications. Bisher konnte man Single-Page-App-Inseln mit Blazor Server, Blazor WebAssembly und Auto-Render-Modus in eine statisch auf dem Server gerenderte Webanwendung einbauen. In .NET 9.0 können Entwicklerinnen und Entwickler nun auch umgekehrt in eine Single-Page-App einzelne statisch komplett auf dem Server gerenderte Webseiten einbauen. Dazu annotiert man eine Razor Component (.razor-Datei) mit:

@page "/impressum"
@attribute [ExcludeFromInteractiveRouting]
…

Wenn dann eine Navigation zu /impressum im Browser erfolgt, wird diese Seite nicht im Client gerendert oder per WebSockets-Verbindung vom Server angefordert, sondern mit einem vollständigen HTTP-Request. In der App.razor-Datei muss das Verhalten aktiviert werden (siehe Listing 2):

<!DOCTYPE html>
<html>
<head>
    ... other head content here ...
    <HeadOutlet @rendermode="InteractiveServer" />
</head>
<body>
    <Routes @rendermode="@InteractiveServer" />
    <script src="_framework/blazor.web.js"></script>
</body>
</html>

@code {
    [CascadingParameter]
    private HttpContext HttpContext { get; set; } = default!;

    private IComponentRenderMode? PageRenderMode
        => HttpContext.AcceptsInteractiveRouting() ? InteractiveServer : null;
}

Listing 2: App.razor einer Blazor-Server-Anwendung mit statisch auf dem Server gerenderten Einzelkomponenten (Quelle: Microsoft)

Beim QuickGrid-Steuerelement in Blazor darf man nun beim Virtualisierungsmodus den Overscan festlegen, der bestimmt, wie viele Zeilen vor oder nach dem aktuell sichtbaren Bereich noch auf Vorrat zu rendern sind. Im Standard sind das drei Zeilen, was sich per Einstellung OverScanCount im Steuerelement-Tag ändern lässt:

<QuickGrid ItemsProvider="itemsProvider" Virtualize="true" OverscanCount="10">
    ...
</QuickGrid>

Für Anwendungen, die mit der GUI-Bibliothek Windows Presentation Foundation (WPF) erstellt wurden, bietet .NET 9.0 auf Windows 11 nun eine automatische Anpassung an das "Look and Feel" des aktuellen Windows-Betriebssystems. Dazu gehören abgerundete Ecken und die Berücksichtigung des eingestellten Windows-11-Themes.

Die neue Darstellung kann man sich in der WPF Gallery ansehen, die es im Microsoft Store als Preview zum Download gibt. Der zugehörige Quellcode für die Anwendung steht auf GitHub zur Verfügung.

Übersicht über die WPF-Steuerelemente in der WPF Gallery

(Bild: Screenshot auf Windows 11 mit Light Theme: Holger Schwichtenberg)

Das plattformneutrale .NET Multi-Platform App UI (.NET MAUI) läuft auch auf der Beta-1-Version von Android 15. Zudem gibt es nun Unterstützung für die Soft-Keyboardeingabe für Datum, Uhrzeit und Kennwörter in den XAML-Steuerelementen <Editor> und <Entry>, zum Beispiel <Entry Keyboard="Date" />, <Editor Keyboard="Time" /> und <Entry Keyboard="Password" />:

Die Einzelansicht eines Steuerelements zeigt auch den zugehörigen XAML-Code.

(Bild: Screenshot auf Windows 11 mit Dark Theme: Holger Schwichtenberg)

Weitere Informationen zu den .NET-Neuerungen finden sich in einem Microsoft-Blogeintrag.

(mai)