.NET 9.0 Preview 5 liefert Verbesserungen für Blazor

Blazor Server bietet verbessertes Wiederherstellen von Verbindungen, einen optimierten Download statischer Ressourcen und leichteres Abfragen des Render-Modus.

In Pocket speichern vorlesen Druckansicht

(Bild: Pincasso/Shutterstock.com)

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

Microsoft hat die fünfte Vorschauversion von .NET 9.0 zum Download bereitgestellt. Entwicklerinnen und Entwickler können nun den Render-Modus bei Blazor-Anwendungen leichter abfragen. Der Blazor Server bietet ein verbessertes Benutzererlebnis beim Wiederherstellen von Verbindungen und der Download statischer Ressourcen wurde optimiert. Darüber hinaus hat Microsoft ein Update der Visual Studio-Version 17.11 auf Preview 2 veröffentlicht.

Einen größeren Fortschritt gibt es in Blazor Server beim Wiederherstellen von Verbindungen. Blazor Server ist eine Variante von Blazor, bei der die Benutzeroberfläche auf dem Webserver erzeugt und mit einem kontinuierlichen Datenaustausch per Websockets so zum Webbrowser übertragen wird, dass der Benutzer das Erlebnis einer Single-Page-App (SPA) erhält – mit Ausnahme der Offline-Fähigkeit, die es bei Blazor Server nicht geben kann.

Microsoft bietet in .NET 9.0 nicht nur eine Überarbeitung der Anzeige beim Verbindungsverlust (siehe Abbildung 1), sondern auch Verbesserungen beim Wiederherstellen der Verbindung. Diese wird nun automatisch wieder aufgenommen, wenn der Benutzer zu einem Browser-Tab zurücknavigiert. Zudem verwendet Microsoft für das Wiederherstellen einer Verbindung nicht mehr Versuche mit linearen, sondern exponentielle Intervalle. Dies lässt sich konfigurieren, wie in Listing 1 zu sehen.

Falls eine Verbindung nicht wiederhergestellt werden kann, weil Blazor Server den Zustand auf dem Webserver bereits verworfen hat oder der Webserverprozess neu gestartet wurde (z.B. beim Austausch des Programmcodes), führt der Browser automatisch ein komplettes Neuladen der Anwendung aus. Das mussten Benutzer bisher manuell anstoßen.

Wenn ein Neuladen der Seiten erfolgen muss, gehen weiterhin der Zustand der Anwendung und alle Formulareingaben des Benutzers verloren. Microsoft präsentierte aber auf der diesjährigen Build-Konferenz im Vortrag "Modern Full-Stack Web Development with ASP.NET Core & Blazor" einen bisher nicht veröffentlichten Prototyp eines neuen Tags <StatefulReconnection> in der App.razor-Datei, mit der bei Blazor Server zumindest die aktuellen Formulareingaben des Benutzers beim Neuladen erhalten bleiben.

Verschönerte modale Anzeige der Neuverbindung bei Blazor Server ab .NET 9.0 Preview 5 (Abb. 1).

(Bild: Screenshot auf Windows 11: Holger Schwichtenberg)

Folgendes Listing von Microsoft zeigt die Konfiguration der Intervalle für die Verbindungsversuche bei Blazor Server:

Blazor.start({
    circuit: {
        reconnectionOptions: {
        retryIntervalMilliseconds: (previousAttempts, maxRetries) => previousAttempts >= maxRetries ? null : previousAttempts * 1000,
        },
    },
});

Seit .NET 8.0 gibt es bei Blazor basierten Browseranwendungen nicht nur die Render-Modi Blazor Server und Blazor WebAssembly, sondern auch Static Server-Side-Rendering und den Auto-Modus, der von Static Server-Side-Rendering zu Blazor Server und Blazor Server zu Blazor WebAssembly umschalten kann. Bisher war es für Entwicklerinnen und Entwickler nur sehr umständlich möglich zu ermitteln, in welchem Modus Blazor gerade rendert.

In .NET 9.0 Preview 5 bietet Microsoft nun in der Basisklasse ComponentBase für alle Razor Components die Eigenschaften Platform mit den Werten Name (string) und IsInteractive (bool) an. Mögliche Zeichenketten bei der Eigenschaft Name sind:

  • "Static" für Static Server-Side-Rendering
  • "Server" für Blazor Server
  • "WebAssembly" für Blazor WebAssembly
  • "WebView" für hybride Blazor-App in WPF, Windows Forms und .NET MAUI

Zudem können Entwicklerinnen und Entwickler über die Eigenschaft AssignedRenderMode innerhalb einer Komponente auslesen, welcher Render-Modus folgen wird. Beispiele dazu zeigen die Abbildung 2 bis 5.

Microsoft hat aber auf GitHub bereits angekündigt, die Eigenschaft Platform in folgenden Preview-Versionen noch in RenderInfo umzubenennen.

Diese Seite wurde statisch auf dem Webserver gerendert. Eingestellt ist aber der Auto-Render-Modus, d.h. ein Übergang zu Blazor Server oder direkt zu Blazor WebAssembly ist in Arbeit (Abb. 2).

Aktuell wird diese Seite mit Blazor Server gerendert und das soll auch so bleiben, zumindest so lange die Seite nicht neu aufgerufen wird (Abb. 3).

Diese Seite wird mit Blazor WebAssembly im Webbrowser gerendert (Abb. 4).

Diese Seite wird statisch auf dem Webserver gerendert und ist via @attribute [Microsoft.AspNetCore.Components.ExcludeFromInteractiveRouting] so eingestellt, dass sie nicht zu einer der interaktiven Blazor-Varianten übergehen wird (Abb. 5).

In .NET 9.0 hat Microsoft das Ausliefern von statischen Webressourcen wie CSS-Dateien, JavaScript-Dateien, Grafiken und Videos optimiert. Die neue Konfigurationsmethode MapStaticAssets() anstelle der bisherigen UseStaticFiles() sorgt für eine Komprimierung (s. Abbildung 6) und das Einfügen von E-Tags mit SHA-256-Hash zur Versionierung von Ressourcen. Damit kann ein Browser erkennen, ob eine Datei in seinem Cache veraltet ist (siehe Abbildung 7).

Verringerung der Netzwerknutzung durch die Komprimierung anhand der Microsoft-Projektvorlage "Blazor Web App" (Abb. 6).

Einsatz von E-Tags für eine Grafik (Abb. 7).

Ab .NET 9.0 Preview 5 liefert Microsoft eine neue Projektvorlage ".NET MAUI Blazor Hybrid and Web App" (siehe Abbildung 8). An der Kommandozeile heißt die Vorlage "maui-blazor-web". Die neue Vorlage erstellt sowohl eine Blazor-Webanwendung (wobei der Render-Modus zwischen "Static", "Server", "WebAssembly" und "Auto" wählbar ist) als auch eine Blazor MAUI-Anwendung. Bei der Auswahl "Auto" entstehen insgesamt die vier in Abbildung 9 gezeigten Projekte:

  • Ein Startprojekt für Blazor MAUI mit XAML-Dateien und < BlazorWebView>
  • Ein Projekt für Webserver
  • Ein Projekt für den Webbrowser
  • Ein "Shared"-Projekt mit den Razor Components

Neue Projektvorlage ".NET MAUI Blazor Hybrid and Web App" für Cross-Platform-Apps (Abb. 8).

Vier Projekte in der neuen Projektvorlage ".NET MAUI Blazor Hybrid and Web App" (Abb. 9).

Für Blazor-basierte Anwendungen steht nun eine einfachere Möglichkeit parat, den serverseitigen Authentifizierungszustand an Blazor WebAssembly im Browser zu übergeben. Dafür gibt es die neue Methode AddAuthenticationStateSerialization() für den Server und AddAuthenticationStateDeserialization() für den Client. Sie sind jeweils im Startcode in Program.cs aufzurufen. Standardmäßig werden dabei der Name und die Rollen des authentifizierten Benutzers per HTML-Kommentar (<!--Blazor-WebAssembly-Component-State:eyJfX2ludGVybmFsX19BdXRoZW50aWNhdGlvb… -->) vom Server zum Browser übergeben. Optional können Entwicklerinnen und Entwickler auch alle Claims so übergeben:

builder.Services.AddRazorComponents()
    .AddInteractiveWebAssemblyComponents()
.AddAuthenticationStateSerialization(options => options.SerializeAllClaims = true);

Bei Entity Framework Core gibt es in Preview 5 nur ein paar kleinere Neuerungen. Der Objekt-Relationale Mapper (ORM) kann nun die .NET-Methoden TimeOnly.FromDateTime() und TimeOnly.FromTimeSpan() in LINQ-Abfragen in SQL übersetzen. Vergleiche mit Count != 0 und Count > 0 übersetzt Entity Framework Core nun in SQL mithilfe von EXISTS statt COUNT, beispielsweise aus folgender LINQ-Abfrage

var blogsWithPost = await context.Blogs
    .Where(b => b.Posts.Count > 0)
.ToListAsync();

wird diese SQL-Abfrage:

SELECT "b"."Id", "b"."Name", "b"."SiteUri"
FROM "Blogs" AS "b"
WHERE EXISTS (
    SELECT 1
    FROM "Posts" AS "p"
    WHERE "b"."Id" = "p"."BlogId")

Über 60 Methoden der .NET-Basisklassenbibliothek, die Parameter-Arrays entgegennehmen, haben nun auch eine Überladung mit ReadOnlySpan<T>, z.B. String.Format(), String.Join() und Console.Writeline().

Dies basiert auf dem neuen Sprachfeature "Params Collections" in C# 13.0, das generische Mengentypen zur Übergabe variadische Parameter bei params erlaubt, was die Geschwindigkeit des Methodenaufrufs verbessern soll. Der C#-Compiler kann die Argumente auf dem Stack speichern, wodurch die implizite Array-Allokation vermieden wird, die sonst angefallen wäre.

Dabei sind folgende generischen Mengentypen bei params in C# 13.0 erlaubt:

  • System.Collections.Generic.IEnumerable<T>
  • System.Collections.Generic.IReadOnlyCollection<T>
  • System.Collections.Generic.IReadOnlyList<T>
  • System.Collections.Generic.ICollection<T>
  • System.Collections.Generic.IList<T>
  • Alle Klassen, die System.Collections.Generic.IEnumerable<T> implementieren
  • System.Span<T>
  • System.ReadOnlySpan<T>

Folgendes Listing zeigt die Params CollectionsF

/// <summary>
 /// Bisher: Parameter-Array
 /// </summary>
 public void MethodeMitbeliebigVielenParametern_Alt(string text, params int[] args)
 {
  CUI.H2(nameof(MethodeMitbeliebigVielenParametern_Alt));
  CUI.Print(text + ": " + args.Length);
  foreach (var item in args)
  {
   CUI.LI(item);
  }
 }
 
 /// <summary>
 /// Neu: Eine Methode mit params-List statt Array
 /// </summary>
 public void MethodeMitbeliebigVielenParametern_Neu(string text, params List<int> args)
 {
  CUI.H2(nameof(MethodeMitbeliebigVielenParametern_Neu));
  CUI.Print(text + ": " + args.Count);  // statt args.Length
  foreach (var item in args)
  {
   CUI.LI(item);
  }
 }
 
 /// <summary>
 /// Neue Überladungen in der Basisklassenbibliothek
 /// </summary>
 public void NeueBCLUeberladungen()
 {
  var p1 = "Dr. Holger Schwichtenberg";
  var p2 = "www.dotnet-doktor.de";
 
  List<string> list = [p1, p2];
 
  Console.WriteLine("{0} = {1}", list);
  var s1 = String.Format("{0} = {1}", [p1, p2]);
  var s2 = String.Join(", ", list);
 }

Die in .NET 8.0 eingeführte Klasse System.Buffers.SearchValues hat nun in der Methode Create() eine Überladung erhalten, um nicht nur einzelne Zeichen, sondern ganze Zeichenketten schnell in einer anderen Zeichenkette zu suchen, siehe Listing 3:

Folgender Code zeigt die Erweiterung bei Create() in der Klasse System.Buffers.SearchValues

// In .NET 8.0 möglich
SearchValues<char> digits = SearchValues.Create("0123456789");
string text1 = "Hinweis: Der Buchstabe A hat in der ASCII-Tabelle den Wert 97.";
var positionDerErstenZiffer = text1.AsSpan().IndexOfAny(digits);
Console.WriteLine(positionDerErstenZiffer); // 59
 
// Ab .NET 9.0 Preview 5 möglich
SearchValues<string> artikel =
SearchValues.Create(["der", "die", "das"], StringComparison.OrdinalIgnoreCase);
string text2 = "Hinweis: Der Buchstabe A hat in der ASCII-Tabelle den Wert 97.";
var positionDesErstenArtikels = text2.AsSpan().IndexOfAny(artikel);
Console.WriteLine(positionDesErstenArtikels); // 9

In der Klasse System.Threading.Tasks.Task hat Microsoft die Methoden WhenEach() neu eingeführt, die ein IAsyncEnumerable<Task> liefert und eine foreach-Schleife jeweils durchläuft, sobald ein Ergebnis einer Hintergrundaufgabe bereitsteht. In Listing 4 wird dies verwendet, um den Status von drei HTTP-Anfragen sukzessive zu ermitteln.

Folgender Code zeigt den Einsatz von WhenEach()

using HttpClient http = new();
 
Task<HttpResponseMessage> t1 = http.GetAsync("http://www.dotnetframework.de");
Task<HttpResponseMessage> t2 = http.GetAsync("http://www.dotnet8.de");
Task<HttpResponseMessage> t3 = http.GetAsync("http://www.dotnet9.de");
 
await foreach (Task<HttpResponseMessage> t in Task.WhenEach(t2, t1, t3))
{
 Console.WriteLine($"{DateTime.Now.ToLongTimeString()}: {t.Result.RequestMessage.RequestUri} = {t.Result.StatusCode}");
}

Zudem stellt Microsoft in .NET 9.0 die neue Methode CreateUnboundedPrioritized<T> in der Klasse System.Threading.Channels.Chanel sowie eine neue Klasse TypeName im NuGet-Paket "System.Reflection.Metadata" bereit. Details dazu finden sich in den Release Notes.

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.

.NET MAUI unterstützt nun die Beta 2-Version der Android API-Version 35. Durch Einsatz von LLVM Marshalled Methods soll auf Android eine Leistungsverbesserung von 10 Prozent erreicht werden. Beim zuvor eingeführten Trimming wurden zudem Fehler behoben.

(map)