WebAssembly-Programmierung mit ASP.NET Blazor

Das Browser-Plug-in Silverlight ist seit 2012 Geschichte. Microsoft wagt nun mit ASP.NET Blazor einen neuen Versuch, .NET im Browser auszuführen. Es ist für viele .NET-Entwickler interessant, die sich mit der JavaScript-Welt nicht anfreunden wollen.

Werkzeuge  –  6 Kommentare
WebAssembly-Programmierung mit ASP.NET Blazor

Von 2007 bis 2012 gab es für Microsoft bereits ein .NET für den Browser. Es nannte sich Silverlight und verwendete die eXtensible Application Markup Language (XAML) als Oberflächenbeschreibungssprache. Silverlight wurde erst mit sehr viel Energie vorangetrieben und von Microsoft enthusiastisch beworben, dann aber nach Version 5.1 plötzlich zugunsten der Webprogrammierung mit HTML und JavaScript beziehungsweise dem darauf aufsetzenden TypeScript eingestellt.

ASP.NET Blazor ist ein anderes Konzept. Im Gegensatz zu Silverlight ist hierfür kein Browser-Plug-in notwendig und Blazor verwendet auch nicht XAML, sondern das im Web etablierte HTML und CSS für die Oberflächenbeschreibung.

WebAssembly

Blazor basiert auf dem neuen Standard WebAssembly (WASM). WASM ist ein Bytecode und eine zugehörige Laufzeitumgebung zur Ausführung in Webbrowsern als Alternative zu JavaScript – ebenfalls in der Sandbox des Browsers. Das World Wide Web Consortiuum (W3C) verwaltet den WASM-Standard. Derzeit ist der Status Working Draft (Stand 15. Februar 2018), dennoch haben einige aktuelle Versionen der Webbrowser Firefox (ab Version 58), Chrome (ab Version 63), Edge (ab Version 16) und Safari (ab Version 11.2) WASM schon implementiert.

WASM ist nicht als Ersatz, sondern als Ergänzung zu JavaScript gedacht, um komplexere Berechnungen performanter mit einer Low-Level-Sprache ausführen zu können. In WASM ist zwar Interoperabilität zu JavaScript vorgesehen, das heißt, JavaScript kann WASM-Code aufrufen und umgekehrt, aber WASM hat keinen Zugriff auf das Document Object Model (DOM) des Browsers.

Architektur von Blazor

Dennoch hat Microsoft mit Blazor ein Produkt geschaffen, mit dem man das Browser-DOM aus WASM verändern und auf JavaScript verzichten kann. Kern von Blazor ist die auf WASM portierte Mono Runtime. Mono ist eine Variante des .NET-Frameworks, die Miguel de Icaza seit 2001 maßgeblich unabhängig von Microsoft entwickelte. Im Jahr 2016 gelangte sie durch die Übernahme der Firma Xamarin aber auch zu Microsoft.

Abbildung 1 zeigt die Architektur von Blazor. Der Softwareentwickler schreibt C#-Programmcode. Dieser wird entweder in WASM-Bytecode (AOT Compiled Mode) oder wie bisher in Microsoft Intermediate Language (Interpreted Mode) kompiliert. In dem C#-Programmcode kann der Entwickler .NET-Assemblies (DLLs) referenzieren. Die Mono Runtime bildet die Ausführungsumgebung. Sie liegt auf jeden Fall in WASM-Bytecode vor: Die aktuelle Version verwendet immer den Interpreted Mode. Es kommt der Mono Linker zum Einsatz, der nicht verwendeten Programmcode auch aus den verwendeten Bibliotheken eliminiert. Aus diesem Grund dauert die Kompilierung bei Blazor beim ersten Mal länger als es bei anderen Projektarten üblich ist.

Der Programmierer definiert in seinem Programmcode sogenannte Razor Views, die aus HTML, CSS und der Razor-Vorlagensyntax bestehen, die ASP.NET auch auf dem Server (in Model View Controller und Razor Pages) verwendet. Diese Razor Views greifen nicht direkt auf das DOM des Browsers zu, sondern manipulieren ein Abbild des DOM (Shadow DOM). Mit zwei von Microsoft mitgelieferten JavaScript-Dateien (mono.js und blazor.js) wird die Mono-Runtime geladen, der .NET-Code gestartet und das Shadow DOM mit dem eigentlichen Browser-DOM synchronisiert.

Abbildung 1: Architektur von ASP.NET Blazor

Erste Schritte mit ASP.NET Blazor

Aktuell ist die Version 0.3 von Blazor, die am 2. Mai 2018 erschienen ist. Für ASP.NET Blazor benötigt man derzeit (dies kann und wird sich aber ändern):

Ein neues Blazor-Projekt legt der Entwickler dann in Visual Studio über New Project/C#/.NET Core Web Application an (Abbildung 2). Hier kann man zwischen einem reinen Client-Projekt (Vorlage "Blazor") oder einem Client-Projekt mit Web-API-Server-Projekt wählen, das ASP.NET Core verwendet, sowie einer zwischen Client und Server gemeinsamen DLL (Shared Library) auf Basis von .NET Standard 2.0. Die Eingruppierung in die Rubrik .NET Core ist eigentlich falsch, denn ASP.NET Blazor basiert nicht auf .NET Core, sondern, wie eingangs erwähnt, auf Mono. Microsoft arbeitet freilich daran, .NET Core und Mono zu vereinen. Die Auswahl eines Authentifizierungsmechanismus oder das Hosting in einem Docker-Container ist für Blazor-Projekte bisher nicht verfügbar.

Abbildung 2: Anlegen eines Blazor-Projekts in Visual Studio 2017 Update 7

Alternativ kann man die .NET Core-Kommandozeile verwenden. Zunächst installiert man die Projektvorlagen:

dotnet new -i Microsoft.AspNetCore.Blazor.Templates

Dann legt man ein neues Projekt an und startet es:

dotnet new blazor -o BlazorWeb
cd BlazorApp1
dotnet run

Beispielprojekt von Microsoft

Hier soll zunächst das Blazor-Projekt beschrieben werden, dass durch die Visual Studio-Vorlage "Blazor (ASP.NET Core hosted)" angelegt wird. Abbildung 3 zeigt die entstandene Projektstruktur für ein Blazor-Projekt mit Client und Server inklusive Shared Code Library. Während der Server ein .NET Core-Projekt ist, basieren Client und Shared Code Library auf .NET Standard 2.0; damit laufen sie sowohl auf .NET Core als auch auf Mono. Die .NET Standard 2.0-Projekte können .NET-Assemblies referenzieren, die kompatibel zu .NET Standard 2.0 sind. .NET-Bibliotheken, die nicht im Rahmen der Sandbox laufen können (zum Beispiel Datenzugriffskomponenten wie ADO.NET und Entity Framework Core) sind jedoch nicht im Browser lauffähig.

Abbildung 3: Entstandene Projektstruktur für ein Blazor-Projekt mit Client und Server

Die Seite wwwroot/index.html startet den Client. Dort findet man den Tag <script type="blazor-boot"></script>, der aber beim Kompilieren durch folgendes ersetzt wird:

<script src="_framework/blazor.js" 
main="MWABuchBlazor.Client.dll"
entrypoint="MWABuchBlazor.Client.Program::Main"
references="Microsoft.AspNetCore.Blazor.Browser.dll,Microsoft.AspNetCore.Blazor.dll,Microsoft.Extensions.DependencyInjection.Abstractions.dll,Microsoft.Extensions.DependencyInjection.dll,mscorlib.dll,MWABuchBlazor.Shared.dll,netstandard.dll,System.Core.dll,System.dll,System.Net.Http.dll" linker-enabled="true"></script>

Dies führt dazu, dass der Browser die genannten JavaScript- und DLL-Dateien vom Webserver nachlädt (Abbildung 4). In Organisationen, wo das Herunterladen von DLLs per Firewall unterbunden wird, können Blazor-Webanwendungen aktuell nicht laufen. Microsoft ist sich dessen aber bewusst und will dazu später eine Lösung liefern.

Abbildung 4: Beim Start einer Blazor-Anwendung in den Browser geladene Dateien

Die zu Beginn darzustellenden Inhalte bestimmt die Datei /Pages/Index.html, die, wie man es von ASP.NET Core kennt, per _ViewImports.cshtml den Verweis auf eine Layoutseite (Masterpage) in /Shared/MainLayout.chtml erhält. MainLayout.cshtml bildet das Grundlayout der Anwendung und bindet das Menü (linke Seite in Abbildung 5) ein, das in der Datei /Shared/NavMenu.cshtml realisiert ist. Dort sieht man spezielle <NavLink>-Tags, die Blazor in <a>-Tags umwandelt. Alternativ kann der Entwickler das <a>-Tag auch direkt verwenden.

Die Vorlage erstellt eine Single-Page-Application mit drei Ansichten:

  1. Home (/Pages/Index.cshtml) ist eine statische Startseite.
  2. Counter (/Pages/Counter.cshtml) realisiert einen einfachen Zähler, der im Browser bei jedem Klick auf eine Schaltfläche erhöht wird.
  3. Fetch Data (/Pages/FetchData.chtml, Abbildung 4 holt Daten von dem Web-API im Server-Projekt. Die Datumsausgaben sind derzeit immer amerikanisch, auch wenn der Browser auf Deutsch eingestellt ist.

Eine Blazor-Webseite wird also aus MainLayout.chtml, NavMenu.cshtml sowie einer der Ansichten zusammengestellt. Analog zu Googles SPA-Framework Angular nennt auch Microsoft diese einzelnen Seitenbestandteile Komponenten.

Abbildung 5: Das Web-API liefert zufällig erzeugte Wetterdaten. Hier im Chrome-Browser gezeigt.

Listing 1 zeigt den Tag- und Programmcode aus FetchData.cshtml. Hierbei kommt HTML in Verbindung mit der ASP.NET Razor-Syntax zum Einsatz. C#-Ausdrücke und -Befehle sowie spezielle Razor-Direktiven werden dabei immer mit einem Klammeraffen @ eingeleitet. Innerhalb der Razor-Ausdrücke können wieder HTML-Tags eingebettet sein. Visual Studio stellt IntelliSense-Eingabeunterstützung überall in der Vorlage sowohl für HTML und CSS als auch C# bereit. In den von der Projektvorlage generierten Dateien liegt der C#-Programmcode komplett in der .cshtml-Datei; dieser Artikel zeigt später, dass auch eine Trennung von Vorlage und Logik möglich ist.

In der asynchronen Seitenlebenszyklusmethode OnInitAsync() ruft der Client die auf ASP.NET Core-basierende REST-API auf, die man im Serverprojekt im /Controllers/SampleDataController.cs findet. Für den HTTP-Aufruf verwendet der Client die in .NET übliche Klasse Systen(!!!System?).Net.Http.HttpClient. Eine Instanz dieser Klasse erhält die Seite über das in Blazor eingebaute Dependency-Injection-Framework und die Direktive @inject zu Beginn der Datei (siehe dritte Zeile in Listing 1). Anders als im serverseitigen ASP.NET verwendet Microsoft für die JSON-Serialisierung und -Deserialisierung hier aktuell SimpleJSON statt Newtonsoft JSON.NET, da es damit noch Probleme gibt.

Listing 1: FetchData.chtml

@using BlazorWeb.Shared
@page "/fetchdata"
@inject HttpClient Http

<h1>Weather forecast</h1>

<p>This component demonstrates fetching data from the server.</p>

@if (forecasts == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class="table">
<thead>
<tr>
<th>Date</th>
<th>Temp. (C)</th>
<th>Temp. (F)</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
@foreach (var forecast in forecasts)
{
<tr>
<td>@forecast.Date.ToShortDateString()</td>
<td>@forecast.TemperatureC</td>
<td>@forecast.TemperatureF</td>
<td>@forecast.Summary</td>
</tr>
}
</tbody>
</table>
}

@functions {
WeatherForecast[] forecasts;

protected override async Task OnInitAsync()
{
forecasts = await Http.GetJsonAsync<WeatherForecast[]>("/api/SampleData/WeatherForecasts");
}
}

Erweiterung des Wettervorhersagebeispiels

Das Beispiel soll nun um eine Eingabeseite erweitert werden, auf der der Benutzer die Wettervorhersagen nach Belieben auf sein Wunschwetter ändern kann. Dafür wird zunächst einmal in die Tabelle in FetchData.cshtml in die erste Spalte ein Hyperlink zu einer noch anzulegenden Detailseite /edit eingebaut. Da die vom Server gelieferten Datensätze als Primärschlüsselwert das Datum verwenden, wird das Datum in der URL an die Eingabeseite übergeben. Dabei ist zu beachten, dass der Schrägstrich in den amerikanischen Datumsangaben vom Browser als Trennzeichen betrachtet würde: Daher werden die Schrägstriche per Replace() in Unterstriche verwandelt. Alle aus .NET bekannten Methoden zur Bearbeitung von elementaren Datentypen sowie viele Hilfsklassen von .NET stehen in ASP.NET Blazor bereits zur Verfügung.

<td><a 
href="/edit/@forecast.Date.ToShortDateString().Replace("/","_")">@forecast.Date.ToShortDateString()</a></td>

Damit die Folgeseite die Wettervorhersagedaten nicht immer wieder vom Webservice laden muss, soll die Tabellenansicht die Daten nicht nur als lokale Variable, sondern auch in einer statischen Variable speichern. Dazu legt man im Client-Projekt eine neue C#-Klasse an, die AppCache heißt und ein statisches Array-Property mit Namen Forecasts bereitstellt:

using BlazorWeb.Shared;

namespace BlazorWeb.Client
{
public class AppCache
{
public static WeatherForecast[] Forecasts { get; set; }
}
}

Nun wird die OnInitAsync()-Methode der Seite FetchData.cshtml so umgebaut, dass sie in AppCache die Daten ablegt und auch wieder von dort einliest, insofern der Zwischenspeicher gefüllt ist:

@functions {
WeatherForecast[] forecasts;

protected override async Task OnInitAsync()
{
if (BlazorWeb.Client.AppCache.Forecasts != null)
{
forecasts = BlazorWeb.Client.AppCache.Forecasts;
}
else
{
forecasts = await Http.GetJsonAsync<WeatherForecast[]>
("/api/SampleData/WeatherForecasts");
BlazorWeb.Client.AppCache.Forecasts = forecasts;
}
}
}

Im Clientprojekt ist eine neue Blazor-Vorlagenseite anzulegen. Dafür gibt es zurzeit in Visual Studio noch keine Elementvorlage. Am einfachsten kopiert man eine bestehende .cshtml-Seite, beispielsweise die Seite FetchData.cshtml. Die neue Datei soll Edit.cshtml heißen. Im Gegensatz zu den von Microsoft vordefinierten Beispielen in der Vorlage, die HTML und C# in einer Datei vermischen, soll hier gezeigt werden, dass man Ansicht und Logik auch trennen kann, wie man es von ASP.NET Core Razor Pages gewohnt ist.

Daher entsteht eine weitere, reine Codedatei EditModel.cs. Da ausEdit.cshtml (siehe Listing 2) beim Kompilieren eine Klasse mit Namen Edit entsteht, heißt die selbstgeschriebene Klasse EditModel (siehe Listing 3). Die EditModel-Klasse muss von Microsoft.AspNetCore.Blazor.Components.BlazorComponent erben. Die Vorlagendatei muss mit der Direktive @inherits EditModel auf die Modellklasse verweisen.

In der @page-Direktive in der Vorlagenseite ist die URL zu deklarieren, auf die die Seite reagieren soll. Angaben in geschweiften Klammern sind Platzhalter wie {ID}. Der Name der Datei ist für das Routing nicht relevant. Gleichwohl ergibt es Sinn, Dateiname und Route konsistent zu halten.

Der in der Route verwendete Parameter ID (siehe Listing 3) ist als Property mit der Annotation [ParameterAttribute] zu deklarieren. Vergisst man diese Annotation, wird die Seite nicht aufgerufen. Immerhin zeigt die Entwicklerkonsole des Browsers die Fehlermeldung: "Uncaught Error: System.InvalidOperationException: Object of type 'BlazorWeb.Client.Pages.Edit has a property matching the name 'ID', but it does not have [ParameterAttribute] applied."

Der Parameter ID ist mit dem Datentyp string deklariert, da ja eine Zeichenkette mit Unterstrichen bei der Seite ankommt. Nach der Rückersetzung der Unterstriche in Schrägstriche kann die Zeichenkette mit der in .NET üblichen TryParse()-Methode in ein DateTime-Objekt verwandelt werden und mit dem Datum kann der Entwickler dann aus dem Cache den gewünschte Datensatz extrahieren.

Dabei kommt die in .NET etablierte universelle Abfragebibliothek "Language Integrated Query" (LINQ) zum Einsatz, mit der Operation SingleOrDefault(), die genau ein passendes Objekt in dem Array erwartet. Sie liefert null, falls es kein Objekt gibt. Sie erzeugt einen Laufzeitfehler, falls es mehr als ein passendes Objekt gibt.

Falls nicht alles wie erwartet läuft, beispielsweise die ID nicht in ein Datum umwandelbar ist, der Zwischenspeicher leer ist oder gar kein Vorhersageobjekt für das gewünschte Datum enthält, schickt der Programmcode den Benutzer mit UriHelper.NavigateTo("/fetchdata") zurück zur Tabellenansicht. Die notwendige Instanz von UriHelper erhält die Modellklasse per Dependency Injection: [Inject] funktioniert in der .cs-Modellklasse analog zu einem @inject in der .cshtml-Vorlagendatei.

HTML-Eingabemasken

In der Eingabemaske in Listing 2 kommen <input>-Tags mit dem Erweiterungsattribut bind zum Einsatz, das auf die zu bindende Property aus dem Objekt verweist. Es handelt sich um eine Zwei-Wege-Datenbindung, das heißt, der aktuelle Wert aus dem Objekt wird in dem Textfeld dargestellt und durch den Benutzer geänderte Werte im Textfeld wandern automatisch auch in das gebundene Objekt. Den Fahrenheit-Wert kann der Benutzer in der Maske nicht eingeben, denn in der von Microsoft realisierten Klasse WeatherForecast besitzt die Property TemperatureF keinen Setter. Der Wert wird sinnvollerweise aus dem Property TemperatureC errechnet.

Die zweispaltige Darstellung ist nicht wie Microsoft es vormacht in FetchData.cshtml mit dem <table>-Tag, sondern mit dem auf CSS Flexbox aufbauenden $(LEhttps://getbootstrap.com/docs/4.0/layout/grid/:Bootstrap 4-Grid-Layout) realisiert. Die CSS-Klassen von Bootstrap 4 sind verfügbar, weil Bootstrap bereits in /wwwroot/index.html durch die Projektvorlage eingebunden wird.

Die Speichern-Schaltfläche realisiert ein <button>-Tag, dessen onclick()-Ereignis auf eine Methode in der Blazor-Seite verweist. Die Save()-Methode könnte nun das Ergebnis zum Server senden. Derzeit stellt der Server dafür aber keine Operation bereit. Das soll hier auch nicht implementiert werden, da es um den Client geht. Daher schickt die Save()-Methode den Benutzer einfach zurück zur Tabelle, wo er den geänderten Datensatz dann sieht.

Listing 2: Quellcode für die Vorlagenseite Edit.cshtml.
@using BlazorWeb.Shared
@page "/edit/{ID}"
@inherits EditModel

<h1>Weather forecast for @ID of @BlazorWeb.Client.AppCache.Forecasts.Length forecasts</h1>

@if (forecast == null)
{
<p><em>Loading...</em></p>
}
else
{
<div class="row">
<div class="col-3">
Date:
</div>
<div class="col">
<input placeholder="C" value="@forecast.Date.ToShortDateString()" readonly class="form-control" />

</div>
</div>

<div class="row">
<div class="col-3">
TemperatureC:
</div>
<div class="col">
<input placeholder="C" bind="forecast.TemperatureC" class="form-control" />
</div>
</div>

<div class="row">
<div class="col-3">
Summary:
</div>
<div class="col">
<input placeholder="C" bind="forecast.Summary" class="form-control" />
</div>
</div>
<button onclick=@Save class="btn btn-success">Save</button>
}
Listing 3: Quellcode für das Modell zu Edit.cshtml in der Datei EditModel.cs
using BlazorWeb.Shared;
using Microsoft.AspNetCore.Blazor.Browser.Interop;
using Microsoft.AspNetCore.Blazor.Components;
using System;
using System.Linq;
using System.Threading.Tasks;

namespace BlazorWeb.Client.Pages
{
public class EditModel : BlazorComponent
{
[Inject]
Microsoft.AspNetCore.Blazor.Services.IUriHelper UriHelper { get; set; }

[ParameterAttribute]
public string ID { get; set; }
DateTime currentDate;

public WeatherForecast forecast;

protected override async Task OnInitAsync()
{
ID = ID.Replace("_", "/");

if (DateTime.TryParse(ID, out currentDate) && BlazorWeb.Client.AppCache.Forecasts != null)
{
forecast = BlazorWeb.Client.AppCache.Forecasts.Single(x => x.Date == currentDate);
if (forecast != null) return;
}

// all other cases: Show table!
UriHelper.NavigateTo("/fetchdata");
}

protected void Save()
{
// TODO: Data could be sent to the save if we had an operation for this :-)
if (Confirm($"Save your new forecast for {currentDate:d}?", "By confirming, you will be redirected to the table.")) { UriHelper.NavigateTo("/fetchdata"); }
}

private bool Confirm(string text1, string text2 = "")
{
if (RegisteredFunction.Invoke<bool>("confirm", text1, text2))
{
// TODO: other reactions
return true;
}
else
{
// TODO: other reactions
return false;
}
}
}
}

Interoperabilität mit JavaScript

Die Save()-Methode fragt allerdings vorher noch nach, ob der Benutzer wirklich speichern will. Dazu kommt die JavaScript-Funktion confirm() zum Einsatz – einfach um zu zeigen, dass man aus Blazor heraus JavaScript aufrufen kann. Der JavaScript-Aufruf erfolgt über die statische Invoke()-Methode des eingebauten Objekts Microsoft.AspNetCore.Blazor.Browser.Interop.RegisteredFunction. Bei Invoke() ist als erster Parameter der Funktionsname festzulegen. Alle weiteren Parameter werden an JavaScript übergeben.

Allerdings kann man so nicht direkt die confirm()-Funktion von JavaScript adressieren. Der Entwickler muss einen clientseitigen Wrapper bereitstellen, der per Methode registerFunction() in dem von Blazor.js bereitgestellten Blazor-Objekt die gewünschte JavaScript-Methode aufruft.

<script>
Blazor.registerFunction('confirm', (text1, text2) => {
return confirm(text1 + "\n" + text2);;
});
</script>

Diesen Wrapper sollte man nicht in die Komponentendatei einbauen, weil das Probleme mit dem virtual DOM bereitet. Stattdessen sollte man ihn in /wwwroot/index.html unter das Tag <script type="blazor-boot"> </script> einfügen. Abbildung 6 zeigt die neu erstellte Seite mit dem Bestätigungsdialog.

Abbildung 6: Die neu erstellte Eingabemaske im Firefox ausgeführt

Es ist umgekehrt auch möglich, aus JavaScript heraus eine C#-Methode aufzurufen. Außerdem erlaubt Blazor schon heute, Webkomponenten oder Teile davon komplett in C#-Programmcode zu erzeugen, ganz dynamisch ohne eine Razor-Vorlagenseite. Neben onclick() unterstützt Blazor seit Version 0.3 zahlreiche DOM-Ereignisse (siehe Quellcode).

Fazit und Ausblick

Dieser Artikel hat gezeigt, dass man bereits mit der aktuellen Version 0.3 von ASP.NET Blazor die wichtigsten Szenarien einer Single-Page-Application (Komponenten, Vorlagen, Datenbindung, Ereignisse, Routing) realisieren kann. Dennoch fehlen einige Möglichkeiten: Funktionen zur Benutzerverwaltung und Authentifizierung sind bisher nicht vorimplementiert und nicht, wie man von serverseitigen ASP.NET-Projekten kennt, beim Anlegen eines Projekts generierbar. Geplant sind auch zahlreiche Features rund um Formulare und Validierung. Ältere Browser wie der Internet Explorer, die kein WASM unterstützen, sollen Blazor über eine Emulation via asm.js ausführen können. Die gravierendste Schwäche von Blazor ist jedoch, dass es bisher kein Debugging gibt. Microsoft arbeitet aber daran. Außerdem gibt es noch keine offizielle Dokumentation, sondern nur den in C# und TypeScript geschriebenen Quellcode auf Github. Die von Rainer Stropek betriebene Website Learn-Blazor schließt aber diese Dokumentationslücke.

Microsoft spricht bei dem Blazor-Projekt selbst noch von "experimentell" und "Pre-Alpha". Eine echte Webanwendung sollte man damit also noch nicht implementieren. Wenn es Microsoft gelingt, Blazor so komfortabel und performant wie das Server Side Rendering (SSR) mit ASP.NET Core MVC und ASP.NET Core Razor Pages zu machen, könnte Blazor in den kommenden Monaten für die bestehende .NET-Entwicklergemeinde eine echte Alternative zur SPA-Entwicklung mit JavaScript/TypeScript werden. Softwareentwickler aus der .NET-Welt könnten dann auf dem Client die gleiche Programmiersprache und die gleiche Template-Syntax wie auf dem Webserver verwenden und nicht nur ihr Know-how, sondern auch Softwarebibliotheken als "Shared Library" in Server und Client gleichzeitig einzusetzen.

Die Gefahr, dass Microsoft wie bei Silverlight daran scheitert, dass das Browser-Plug-in nicht ausreichende Verbreitung findet, ist hier nicht gegeben, denn man braucht kein Plug-in. Blazor basiert auf dem Webassembly-Standard, der gerade auch in anderen Hochsprachen wie C, C++, Go und Rust immer besser unterstützt wird. (bbo)

Holger Schwichtenberg
leitet das Expertennetzwerk www.IT-Visions.de, das Beratung, Schulungen und Softwareentwicklung im Umfeld von Microsoft-, Java- und Web-Techniken anbietet. Er selbst schreibt Software in C# und JavaScript/TypeScript, hält Vorträge auf Fachkonferenzen und ist Autor zahlreicher Fachbücher.