.NET 8.0 wird das Mischen von Blazor Server und Blazor WebAssembly erlauben

Die Vorschauversion .NET 8.0 Preview 6, die zeitgleich mit Visual Studio 2022 17.7 Preview 3 erschienen ist, macht Blazor wesentlich flexibler.

In Pocket speichern vorlesen Druckansicht 3 Kommentare lesen

(Bild: Shutterstock)

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

Microsoft hat die sechste Preview für .NET 8.0 veröffentlicht. Sie bringt unter anderem vereinfachte Formulare und ZIP-Verbesserungen und ermöglicht das Mischen von Blazor Server und BlazorWebAssembly. Bereits in Preview 5 hatte Microsoft Single-Page-App-Inseln mit Blazor Server beim Server-Side Rendering von Razor Components eingeführt. Solche Projekte konnten Entwicklerinnen und Entwickler aber bisher nur per Kommandozeile anlegen:

dotnet new blazor --use-server -o Projektname

In Visual Studio 2022 Version 17.7 Preview 3 gibt es dafür nun auch eine sprechende Option in der Entwicklungsumgebung (Abb. 1).

Anlegen von Blazor-Projekten mit Server-Side Rendering und SPA-Inseln (Abb. 1).

Während man in Preview 5 die SPA-Inseln nur in der Komponente selbst festlegen konnte via

@attribute [RenderModeServer]

kann dies nun auch in jeder aufrufenden Komponente geschehen:

<Counter @rendermode="@RenderMode.Server" />

Voraussetzung dafür ist, dass man in der Projektdatei nicht nur das Target Framework aufsetzt, sondern auch die Razor-Syntax explizit auf Version 8.0 stellt:

<Project Sdk="Microsoft.NET.Sdk.Web">
 
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
   <RazorLangVersion>8.0</RazorLangVersion>
…
  </PropertyGroup>
 
</Project>

Eine weitere Voraussetzung für die neue Option zum Festlegen des Render-Modus besteht darin, in der Startdatei Program.cs bei

app.MapRazorComponents<App>();

noch den Aufruf der Methode AddServerRenderMode() zu ergänzen:

app.MapRazorComponents<App>().AddServerRenderMode()

Wenn man diesen Aufruf nicht manuell ergänzt, funktioniert die Komponente nicht und meldet in der Browserkonsole nur "SyntaxError: Unexpected end of JSON input".

Es ist zudem nicht möglich, gleichzeitig den Render-Modus in der Komponente und beim Aufrufer festzulegen. Das quittiert Blazor mit diesem Laufzeitfehler: "The component type Counter has a fixed rendermode of Microsoft.AspNetCore.Components.Web.ServerRenderMode, so it is not valid to specify any rendermode when using this component.".

Während in .NET 8.0 Preview 5 die SPA-Inseln nur mit Blazor Server möglich waren, bietet Microsoft in Preview 6 an dieser Stelle alternativ jetzt auch Blazor WebAssembly an. Bisher gibt es für diese Konstellation keine Projektvorlage, man kann aber die Projektvorlage "Blazor Web App" dazu manuell umbauen. Zunächst einmal muss man dieses NuGet-Paket referenzieren:

<ItemGroup>
  <PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="8.0.0-preview.6.23329.11" />
</ItemGroup>

Dann muss man in der Startdatei Program.cs die Methode AddWebAssemblyComponents() aufrufen nach AddRazorComponents():

builder.Services.AddRazorComponents().AddWebAssemblyComponents();

sowie die Methode AddWebAssemblyRenderMode() nach MapRazorComponents<App>() nutzen:

app.MapRazorComponents<App>().AddWebAssemblyRenderMode();

Eine weitere Voraussetzung ist, dass sich alle mit Blazor WebAssembly zu rendernden Razor-Komponenten in einer separaten DLL befinden, die das SDK Microsoft.NET.Sdk.BlazorWebAssembly referenziert:

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

Es ist zu hoffen, dass die Notwendigkeit solch einer Auslagerung in kommenden Vorschauversionen noch entfällt.

Nun ist es möglich, eine Komponente aus dieser DLL mit dem Render-Modus "WebAssembly" zu nutzen:

<Counter @rendermode="@RenderMode.WebAssembly" />

Alternativ kann diesen Render-Modus auch die Komponente selbst deklarieren:

@attribute [RenderModeWebAssembly]

Im Standard werden solche WebAssembly-Komponenten serverseitig vorgerendert. Das können Entwicklerinnen und Entwickler bei Bedarf ausschalten:

@attribute [RenderModeWebAssembly(prerender: false)] 

beziehungsweise

<Counter @rendermode="@(new WebAssemblyRenderMode(prerender: false))

Ein funktionierendes Beispiel für die Integration von Blazor WebAssembly in einer Blazor-Server-Side-Rendering-Anwendung findet man auf GitHub.

Heise-Konferenz: betterCode() .NET 8.0
betterCode() .NET 8.0, Online-Konferenz, 21. November 2023

Mit .NET 8.0 erscheint die nächste Long-Time-Support-Version. Am 21. November 2023 bietet die von Heise und www.IT-Visions.de präsentierte Online-Konferenz betterCode() .NET 8.0 das Rüstzeug, sich einen grundlegenden Überblick zu .NET 8.0 zu verschaffen. Die Expertenvorträge zeigen die Neuerungen in .NET 8.0, ASP.NET Core 8.0, Blazor 8.0, .NET MAUI, C# 12.0 und mehr. Vier ganztägige Workshops vermitteln Hands-on-Wissen.

Zudem kann man nun leicht Blazor Server und Blazor WebAssembly innerhalb einer einzigen Komponente mischen. Dazu aktiviert man in der Startdatei beide Render-Modi nacheinander:

builder.Services.AddRazorComponents().AddWebAssemblyComponents().AddServerComponents();

und

app.MapRazorComponents<App>().AddWebAssemblyRenderMode().AddServerRenderMode();

Listing 1 zeigt eine Startseite Index.razor, die eine Komponente Counter.razor einmal per Blazor Server und einmal per Blazor WebAssembly einbindet. Abbildung 2 zeigt die Auswirkung auf den Webbrowser: Der Browser baut für Blazor Server eine Websocket-Verbindung auf und lädt danach die WebAssembly-Dateien für Blazor WebAssembly. Die Rahmenkomponente entsteht rein per Server-Side Rendering.

@page "/"
 
<PageTitle>Index</PageTitle>
 
<h1>Heise Developer - Schnelltest .NET 8.0 Preview 6</h1>
(C) Dr. Holger Schwichtenberg 11.07.2023
<hr />
<h3> Counter mit Blazor Server</h3>
 
<div>
<Counter IncrementAmount="2" @rendermode="@RenderMode.Server" />
</div>
<h3> Counter mit Blazor WebAssembly</h3>
 
<div>
<Counter IncrementAmount="2" @rendermode="@RenderMode.WebAssembly" />
</div>

Listing 1: Mischung von Blazor Server und Blazor WebAssembly in einer Seite

Der Browser baut für Blazor Server eine Websocket-Verbindung auf und lädt danach die WebAssembly-Dateien für Blazor WebAssembly (Abb. 2).

Microsoft geht also mit Preview 6 einen großen Schritt weiter in Richtung des am 24. Januar 2023 angekündigten "Blazor United". Es fehlt aber noch der angekündigte Rendering-Modus "Auto", bei dem das Rendering zuerst per Blazor Server erfolgt und dann auf Blazor WebAssembly übergeht.

Microsoft kündigt im Blogeintrag an: "Im Rahmen der Vereinheitlichung der verschiedenen Blazor-Hostingmodelle in einem einzigen Modell in .NET 8 konsolidieren wir auch die Anzahl der Blazor-Projektvorlagen. In dieser Vorschauversion haben wir die Blazor-Server-Vorlage und die Option "ASP.NET Core gehostet" aus der Blazor-WebAssembly-Vorlage entfernt. Beide Szenarien werden durch Optionen dargestellt, wenn die neue Blazor-Web-App-Vorlage verwendet wird." Der Schnelltest zeigt aber, dass das in Preview 6 noch nicht vollzogen ist: Es gibt weiterhin alle bisher bekannten Blazor-Projektvorlagen (Abb. 3).

Blazor-Projektvorlagen in .NET 8.0 Preview 6 (Abb. 3).

Die bisher umständliche Handhabung von Formulareingaben beim Server-Side Rendering in Blazor via CascadingModelBinder und FormData.Entries.TryGetValue() wird ab .NET 8.0 Preview 6 einfacher, indem Entwicklerinnen und Entwickler nun eine Property mit [SupplyParameterFromForm] annotieren können (siehe Listing 2). Alle in der HTTP-Anfrage gelieferten Name-Wert-Paare werden in die dem Namen entsprechenden Properties abgelegt. Die annotierten Properties können einfache Datentypen oder komplexe Typen (Klassen, Strukturen, Records) oder Mengentypen sein. Vorhandene Validierungsannotationen werden berücksichtigt und Validierungsfehlerausgaben sind mit den eingebauten Blazor-Komponenten <ValidationMessage> und <ValidationSummary> möglich.

Zudem bewahrt Blazor beim Server-Side Rendering nun einen Teil des Seiteninhalts, sodass Benutzer weniger Flacker-Effekte sehen. Die in Preview 4 eingeführten Sektionen für Blazor (<SectionOutlet> und <SectionContent>) funktionieren nun auch beim Streaming Rendering sowie in Verbindung mit kaskadierenden Werten und Error Boundaries.

@page "/Registration/"
@using NET8_BlazorSSR;
@layout MainLayout
@inject NavigationManager nav
 
<h3>Bestellung des Fachbuchabos</h3>
<hr />
 
@if (!reg.Success)
{
 <EditForm method="POST" Model="reg" OnValidSubmit="HandleSubmit">
  <DataAnnotationsValidator />
  <p>Ihr Name: <InputText @bind-Value="reg.Name" />   <ValidationMessage For="@(()=>reg.Name)" /></p>
  <p>Ihr E-Mail-Adresse: <InputText @bind-Value="reg.EMail" />   <ValidationMessage For="@(()=>reg.EMail)" /></p>
  <button type="submit">Bestellen</button>
 </EditForm>
}
 
@if (reg.Success)
{
 <div>
  <p>Liebe(r) @reg.Name,</p>
  <p>vielen Dank für Ihre Registrierung zum Fachbuchabo!</p>
  <p><a href="/confirmation/@reg.Name">Bestätigung ausdrucken</a></p>
 </div>
}
@code {
 [SupplyParameterFromForm]
 BookSubscriptionRegistration reg { get; set; }
 
 protected override void OnInitialized()
 {
  reg = new();
 }
 
 
 void HandleSubmit()
 {
  reg.Save();
  reg.Success = true;
 }
 
}

Listing 2: Vereinfachte Formulardatenbindung einschließlich Validierung bei Blazor Server-Side Rendering

In .NET 7.0 hatte Microsoft einen Source Generator für native API-Aufrufe (auf jeder Betriebssystemplattform) per Annotation [LibraryImport] eingeführt. In .NET 8.0 Preview 6 folgt nun eine analoge Möglichkeit für die Nutzung des (nur unter Windows verfügbaren) Component Object Model (COM). Der Wrapper der COM-Schnittstelle muss diese mit [GeneratedComInterface] annotieren. Diese Schnittstellen implementierende Klassen erhalten die Annotation [GeneratedComClass]. Bei der schon in .NET 7.0 eingeführten Annotation [LibraryImport] können Entwicklerinnen und Entwickler nun COM-Schnittstellen als Parameter- und Rückgabetypen verwenden. Durch diese Annotationen erzeugt der C#-Compiler den COM-Zugriffscode, der normalerweise erst zur Laufzeit entsteht, bereits zur Entwicklungszeit. Den generierten Code findet man im Projekt im Ast /Dependencies/Analyzers/ Microsoft.Interop.ComInterfaceGenerator.

Bei vorhandenen Schnittstellen mit Annotation [ComImport] schlägt Visual Studio die Umwandlung in [GeneratedComInterface] vor. Für Klassen, die diese Schnittstellen realisieren, schlägt Visual Studio dann [GeneratedComClass] vor.

Allerdings fehlt im Blogeintrag allen COM-Beispielen zum Thema das Schlüsselwort partial. Microsoft schreibt zum Beispiel:

[GeneratedComInterface]
[Guid("5401c312-ab23-4dd3-aa40-3cb4b3a4683e")]
interface IComInterface
{
 void DoWork();
 void RegisterCallbacks(ICallbacks callbacks);
}

Das führt aber in Visual Studio 17.7 Preview 3 mit .NET 8.0 Preview 6 zum Compilerfehler: "The interface IComInterface or one of its containing types is missing the partial keyword. Code will not be generated for IComInterface."

Korrekt ist:

[GeneratedComInterface]
[Guid("5401c312-ab23-4dd3-aa40-3cb4b3a4683e")]
partial interface IComInterface
{
 void DoWork();
 void RegisterCallbacks(ICallbacks callbacks);
}

Ferner dokumentiert Microsoft einige Einschränkungen des Source Generators für COM. Dazu gehört, dass der Generator nicht für IDispatch- und IInspectable-basierte Schnittstellen funktioniert und weder COM-Properties noch COM-Events unterstützt. Zudem können Entwicklerinnen und Entwickler eine COM-Klasse nicht mit dem Schlüsselwort new aktivieren, sondern nur per Aufruf von CoCreateInstance(). Diese Beschränkungen sollen auch in der endgültigen Version von .NET 8.0, die im November 2023 erscheinen soll, noch gelten und gegebenenfalls erst in einer späteren Hauptversion verbessert werden.

Die Klasse System.IO.Compression.ZipFile, die es seit dem klassischen .NET Framework 4.5 und im modernen .NET seit Version .NET Core 1.0 gibt, erhält zwei neue statische Methoden CreateFromDirectory() und ExtractToDirectory(), um ein ZIP-Archiv direkt aus einem Dateisystemordner zu erzeugen beziehungsweise dorthin zu entpacken.

Für das in .NET 7.0 eingeführte Caching von Webserverausgaben bietet Microsoft nun eine direkte Anbindung an Redis. In Verbindung mit dem Einsatz von HTTP.sys als Webserver unter Windows können Entwicklerinnen und Entwickler Response Buffering im Kernel von Windows aktivieren. Microsoft behauptet: "In betroffenen Szenarien kann dies die Reaktionszeiten drastisch von Minuten (oder völligem Ausfall) auf Sekunden verkürzen."

In einem weiteren Blogeintrag widmet sich Microsoft drei neuen Sprachfeatures in C# 12.0:

  • Ein Interceptor erlaubt einen Methodenaufruf abzufangen und umzulenken. Das will Microsoft vor allem einsetzen, um mehr Code kompatibel zum Ahead-of-Time-Compiler zu machen.
  • Der Operator nameof funktioniert jetzt auch mit Mitgliedsnamen, einschließlich Initialisierern, bei statischen Mitgliedern und in Attributen (siehe Listing 3).
  • Zur Optimierung von Arrays gibt es jetzt Inline Arrays.
internal class NameOf
{
    public string S { get; } = "";
    public static int StaticField;
    public string NameOfLength { get; } = nameof(S.Length);
    public static void NameOfExamples()
    {
        Console.WriteLine(nameof(S.Length));
        Console.WriteLine(nameof(StaticField.MinValue));
    }
    [Description($"String {nameof(S.Length)}")]
    public int StringLength(string s)
    { return s.Length; }
}

Listing 3: Erweiterungen für nameof() (Quelle: Microsoft)

Microsoft bietet für .NET-Apps auf iOS, Mac Catalyst und tvOS nun erstmals eine Kompilierung von .NET-Anwendungen mit dem neuen .NET Native Compiler an. Das ist möglich sowohl für auf diese Plattformen beschränkte Apps (".NET for iOS") als auch beim .NET Multi-platform App UI (.NET MAUI). Die Apps laufen dann nicht mehr auf Mono und die App-Pakete für .NET for iOS werden deutlich kleiner, bei .NET MAUI aber größer (Abb. 4). Microsoft hat laut Aussage im Blogeintrag das Problem erkannt und will es lösen, sodass hier rund 30 Prozent Größenvorteil erreicht werden.

Eine Reihe von Fehlerbehebungen für .NET MAUI thematisiert Microsoft in einem eigenen Blogbeitrag. Außerdem gibt es nun eine erste Fassung einer .NET MAUI-Erweiterung für Visual Studio Code.

Verkleinerte App-Pakete durch Native AOT (Abb. 4).

(Bild: Microsoft)

Die Ankündigung von .NET 8.0 Preview 6 findet sich auf Microsofts Entwicklerblog.

(mai)