Browser + Razor = Blazor

SPA-Framework Blazor bringt C# in den Browser
Keine Kommentare

Zugegeben, Silverlight ist tot. Die Idee, C# und .NET in den Browser zu bringen, ist aber keineswegs gestorben. Microsofts neues Single-Page-App-Framework Blazor nimmt den Gedanken wieder auf. Es basiert auf WebAssembly, einem plattformunabhängigen W3C-Standard, der von allen großen Browserherstellern bereits unterstützt wird.

In meiner letzten Kolumne habe ich das neue Blazor-Framework von Microsoft kurz vorgestellt. In diesem Artikel sehen wir uns den aktuellen Stand der Entwicklung genauer an. Für viele .NET-Entwicklungsteams ist es eine sehr interessante Perspektive, bestehenden Code und bestehendes Wissen in die Browserwelt mitnehmen zu können – und das ohne Plug-in und auf allen Plattformen. Bisher hatte JavaScript ein Monopol im Bereich clientseitiger Webentwicklung. Als Entwicklerinnen und Entwickler konnten wir zwar auf eine Vielzahl an Frameworks und Sprachen wie Angular, React oder TypeScript zurückgreifen, letztendlich lief es aber immer auf JavaScript hinaus.

WebAssembly verändert die Spielregeln

WebAssembly (kurz Wasm) ändert die Spielregeln im Browser von Grund auf. Wasm ist ein standardisiertes, portables Binärformat für eine virtuelle Maschine. Grundsätzlich könnte Wasm überall laufen, im Augenblick liegt der Fokus aber auf der Ausführung von Wasm-Code im Browser. Alle großen Browser (Edge, Chrome, Firefox und Safari) implementieren Wasm bereits. Das bedeutet, dass Programme, die dem Wasm-Standard entsprechen, ohne Plug-in in diesen Browsern laufen und durch die Browser-Sandbox abgesichert sind. C++ kann in Wasm übersetzt werden, die .NET Common Language Runtime (CLR) ist in C++ programmiert, warum also nicht die CLR in Wasm ausführen? Genau diesen Gedanken hatte 2017 das Mono-Team. Das Ergebnis war ein erster Prototyp der Mono .NET CLR auf Wasm.

Die Rolle von Blazor

Die CLR allein ist nur für sehr wenige Anwendungsfälle relevant. Es fehlt eine Benutzerschnittstelle. Wasm kann in der aktuellen Version nicht direkt auf den DOM zugreifen. Die einzige Kommunikation mit der Außenwelt, die Wasm beherrscht, ist JavaScript Interop. Man kann von Wasm JavaScript-Funktionen aufrufen und umgekehrt. Außerdem können Wasm und JavaScript auf gemeinsame Speicherbereiche zugreifen, um Daten auszutauschen.
Genau an dieser Stelle setzt Blazor an. Die Ziele dieses neuen Open-Source-Single-Page-App-( SPA-)Frameworks, das von Microsoft initiiert und vorwärts getrieben wird, kann man wie folgt zusammenfassen:

  • Durch Aufbau auf der Mono .NET Runtime für Wasm läuft Blazor ohne Plug-in auf allen gängigen Browserplattformen.
  • Als UI-Beschreibungssprache wird die von ASP.NET bekannte Sprache Razor eingesetzt.
  • Die UI-Logik wird in C# entwickelt.
  • Blazor verwendet für die eigentliche UI-Darstellung HTML und CSS. Das Framework hat einen JavaScript-Teil, der C# und DOM verbindet.
  • Das Framework enthält Funktionen für JavaScript Interop, um mit bestehenden JavaScript-Bibliotheken zusammenarbeiten zu können.
  • In SPA-Frameworks übliche Funktionen wie Data Binding, Change Detection, Dependency Injection etc. bringt Blazor von Haus aus mit.
  • Da Blazor auf der ganz normalen .NET CLR aufbaut, kann bestehender C#-Code verwendet werden, sofern er nicht auf Funktionen zugreift, die in der Browser-Sandbox nicht unterstützt werden (z. B. direkter Netzwerkzugriff, Zugriff auf lokale Dateien, Multithreading etc.). Der Code muss nicht einmal neu kompiliert werden. Die vorhandenen DLLs und NuGet-Pakete funktionieren.
  • Die Unterstützung der Entwicklung wiederverwendbarer Bibliotheken mit und ohne JavaScript-Anteil sind ausdrückliches Ziel im Blazor-Projekt. In diesem Artikel gehe ich darauf nicht ein, es würde den Rahmen dieser Einführung sprengen.

Projektstatus

Blazor hat im Moment den Status eines experimentellen Projekts. Das Framework ist daher noch nicht für die Entwicklung produktiver Anwendungen geeignet. Die aktuelle Version ist aber durchaus stabil genug, um erste Prototypen zu entwickeln und Erfahrungen zu sammeln. Seien Sie sich aber der Einschränkungen des aktuellen Entwicklungsstands bewusst. Das API ändert sich noch häufig und teilweise recht grundlegend. Die ersten Dokumentationsseiten gingen erst kürzlich online und haben noch einige Lücken. Hinzu kommt, dass wesentliche Komponenten einer professionellen Entwicklungsplattform, wie zum Beispiel ein Debugger, noch komplett fehlen. Debugging bedeutet im Moment Konsolenausgaben mit Console.WriteLine.

Systemvoraussetzungen und Installation von Blazor

Wer mit Blazor programmieren will, muss die aktuelle Visual-Studio-Preview-Version installieren. Sie kann ohne weiteres parallel zur Produktivversion betrieben werden. Zusätzlich braucht man im Moment noch die Preview-Version von .NET Core 2.1. Erfüllt man diese Systemvoraussetzungen, kann man die Blazor Language Services installieren und loslegen.

Microsoft stellt auch Projektvorlagen für das .NET CLI zur Verfügung. Dadurch lässt sich bereits jetzt auch unter Linux oder MacOS mit Blazor programmieren. Man installiert die Vorlagen mit dotnet new -i Microsoft.AspNetCore.Blazor.Templates. Danach sieht man bei Aufruf von dotnet new die Vorlagen von Blazor und kann in der Kommandozeile neue Blazor-Projekte ohne Visual Studio anlegen, kompilieren und ausführen. Mit Visual Studio Code als Editor braucht man also nicht unbedingt Visual Studio, um mit Blazor zu experimentieren.

Laden einer Blazor-App

Die Struktur eines Blazor-Programms sieht man am besten, wenn man sich den Ladeprozess in den Entwicklungstools des jeweiligen Browsers ansieht. Man sieht in Abbildung 1, dass durch die Startseite (Standarddokument index.html; erste Zeile des Netzwerklogs) die JavaScript-Teile von Blazor (blazor.js) und Mono (mono.js) geladen werden. Sie laden die Wasm-Version der Mono .NET CLR (mono.wasm). Deren Aufgabe ist das Laden der DLLs des .NET Core Frameworks (z. B. netstandard.dll, System.Core.dll, etc.) und der eigentlichen Blazor Anwendung (BlazorPages.dll).

Zu beachten ist, dass es sich um ganz normale .NET DLLs handelt, nicht um Wasm-Code. Im Moment unterstützt Blazor das Übersetzen von C# in Wasm noch nicht. Die DLLs werden von der Mono CLR interpretiert. Auf den ersten Blick scheint das eine wesentliche Performancebremse zu sein. Das lässt sich aber nicht generell sagen. .NET DLLs sind wegen der Mächtigkeit der zugrunde liegenden MSIL relativ klein. Der gleiche Code, kompiliert in Wasm, wäre größer. Man muss daher Downloadgröße und Ausführungsgeschwindigkeit von Fall zu Fall gegeneinander abwägen. Das Blazor-Team hat angekündigt, die Möglichkeit zum Kompilieren von C# in Wasm in einer späteren Version von Blazor anzubieten.

Apropos Größe: Im Web spielt die Größe des Codes eine wesentliche Rolle. Aus diesem Grund verwendet Blazor beim Kompilieren den Mono Linker. Dieser entfernt nicht verwendete Teile von Bibliotheken, um ihre Größe zu reduzieren.

Hosting von Blazor-Apps
Blazor-Apps bestehen wie jede andere SPA-App ausschließlich aus statischen Dateien. Im Vergleich zu Frameworks wie Angular kommen zu den HTML-, CSS- und JavaScript-Dateien noch mono.wasm und .NET DLLs dazu. Blazor hat also keine besonderen Anforderungen an den Webserver. Egal ob IIS, Azure App Service, nginx in einem Docker-Container, GitHub Pages oder Web Server for Chrome, Blazor lässt sich überall hosten. Auch die Verwendung von Blazor in Laufzeitumgebungen wie Electron ist möglich.
In restriktiven Firmenumgebungen stellt der Download von DLLs aus dem Internet oft ein Problem dar. Firewalls stellen sich in den Weg. Das Blazor-Team ist sich dessen bewusst. In der finalen Version von Blazor wird dafür eine Lösung enthalten sein. Im Moment läuft Blazor aber nur in einer Umgebung, die den Download der .NET DLLs ermöglicht.

Abb. 1: Laden einer Blazor-Beispielanwendung

Der Rendering-Prozess

Wenn die Anwendung fertig geladen ist, wird die C#-Main-Methode aufgerufen. Sie finden sie in einem neu generierten Blazor-Programm in der Datei Program.cs (Listing 1). Main startet Blazor, indem sie einen BrowserRenderer anlegt und ihm die UI-Hauptkomponente (App in Listing 1) übergibt. Diese enthält üblicherweise einen Router, mit dem man zwischen den UI-Komponenten seiner Blazor-App navigieren kann. Wir gehen später näher auf den Blazor-Router ein.

 
class Program
{
  static void Main(string[] args)
  {
    var serviceProvider = new BrowserServiceProvider(services =>
    {
      // Register services for dependency injection
      services.AddTransient<IRepository, Repository>();
    });

    new BrowserRenderer(serviceProvider).AddComponent("app");
  }
}

Abb. 2: Rendering-Prozess

Der BrowserRenderer erstellt auf Basis der kompilierten Razor-Templates einen Render Tree. Er wird an den JavaScript-Teil von Blazor übergeben (Abb. 2). Dort werden die entsprechenden DOM-Änderungen durchgeführt. Das Ergebnis von Blazor ist also ganz normales HTML, das mit den bekannten Mitteln von CSS formatiert und bei Bedarf durch Logik in JavaScript ergänzt werden kann (z. B. Verwendung einer bestehenden Library). Eine Einschränkung gibt es dabei jedoch: Die Veränderung der HTML-Struktur ist Blazor vorbehalten. JavaScript-Code, der zum Beispiel eigene HTML-Elemente mitten in den von Blazor erstellten HTML-Objektbaum einfügt, ist nur in Ausnahmefällen mit Blazor kompatibel.

Das Blazor-JavaScript registriert Handler für relevante Events (z. B. Klick auf einen Button) und gibt die Events an den .NET-Teil der App weiter. In den meisten Fällen wird die App in solchen Fällen etwas am internen Status verändern, was Änderungen am UI notwendig macht. Beispiele dafür wären das Anzeigen eines zuvor verborgenen UI-Elements oder die Änderung einer Variable, die mithilfe von Data Binding an das UI gebunden ist. Blazor erkennt solche Änderungen in den meisten Fällen automatisch. Falls nicht, ruft man die Methode StateHasChanged auf, die Blazor signalisiert, dass etwas am DOM zu aktualisieren ist.

Blazor überträgt beim Rendering von Änderungen nicht den gesamten Render Tree wie am Beginn des Programms. Es wird nur eine Beschreibung der notwendigen Änderungen (Render Batch) an JavaScript geschickt, und dort wird das HTML entsprechend verändert.

Blazor Components

Der wichtigste Baustein von Blazor-Apps sind Komponenten. Technisch gesehen sind das Klassen, die von Microsoft.AspNetCore.Blazor.Components.BlazorComponent ableiten. Streng genommen ist das nicht ganz richtig. Blazor-UI-Komponenten müssen Microsoft.AspNetCore.Blazor.Components.IComponent implementieren. In der Praxis wird man jedoch bei eigenen Komponenten nur selten auf dieses Basisinterface zurückgreifen und stattdessen die Basisklasse BlazorComponent verwenden.

Komponenten werden in der Regel über ein Razor-Template generiert. Man kann auf Razor aber auch verzichten und den C#-Code der Komponente selbst schreiben. Das ist beispielsweise hilfreich, wenn die HTML-Struktur über einen Algorithmus generiert statt von Hand Element für Element gestaltet wird.

Abbildung 3 zeigt eine einfache Komponente. Rechts sieht man das Razor-Template und links den C#-Code, den der Blazor-Compiler erstellt. Wer den generierten Code ansehen möchte, findet ihn nach dem Kompilieren im Ordner obj\Debug\netstandard2.0 in den *.g.cs-Dateien. Es ist wichtig für das Verständnis von Blazor, dass Razor-Templates zur Laufzeit keine Bedeutung mehr haben. Sie werden beim Kompilieren vollständig in C#-Code umgewandelt. Die Architektur unterscheidet sich dadurch vom Vorgehen bei anderen UI-Technologien wie WPF mit XAML.

Aufmerksame Leser mit viel .NET-Erfahrung werden sich vielleicht an der Tatsache stören, dass in Razor-Templates View (HTML Template) und Logik (C# im @functions-Abschnitt) gemischt sind. Das muss nicht so sein. Mithilfe der Razor-Anweisung @inherits kann man die Basisklasse der generierten Komponentenklasse verändern. Man kann daher zur besseren Trennung von View und Logik eine C#-Klasse erstellen, die von BlazorComponent ableitet, und die Logik dort implementieren. Anschließend gibt man diese Logikklasse im Razor-Template mit @inherits als Basisklasse an und hat dadurch die gewünschte Trennung. @inherits ist übrigens nicht nur für diesen Zweck praktisch. Man kann diese Razor-Anweisung auch verwenden, um IDisposable zu implementieren.

Partielle Klassen wären theoretisch eine Alternative zu einer Basisklasse, sie werden aber von Blazor im Moment noch nicht unterstützt. In größeren Anwendungen ist der Einsatz eines State Containers möglicherweise sinnvoll. Für Blazor gibt es bereits ein entsprechendes Communityprojekt, das auf Redux.NET basiert.

Abb. 3: Blazor Component

Blazor-Komponenten können andere Komponenten im Razor-Template verwenden. Abbildung 4 zeigt ein Beispiel dafür. Die Komponente ChildComponent wird in EventBinding verwendet. Beachten Sie dabei das Data Binding. Properties aus der Parent Component können an Properties der Child Component gebunden werden. Das gilt nicht nur für einfache Datentypen, sondern auch für komplexere Dinge wie Callback-Funktionen (ChildEventClicked in Abb. 4).

Abb. 4: Child Components

Data Binding

Man kann im Razor-Template auf Variablen des C#-Codes verweisen, um dynamischen Inhalt anzuzeigen. Listing 2 zeigt einige Beispiele dafür. Außerdem enthält dieser Code am Beginn zwei Beispiele für Event Bindings, die verwendet werden, um auf den Klick auf einen Button zu reagieren.

<!-- 
  Event Binding
  Use this button to trigger changes in the source values
-->
<button onclick="@ChangeValues">Change values</button>
<button onclick="@(() => ChangeValues())">Change values</button>

<!--
  Simple interpolation.
  In Angular, this would be {{ Count }}
-->
<p>Counter: @Count</p>

<!--
  Conditionally display content
  In Angular, this would be *ngIf
-->
@if (ShowWarning)
{
  <p style="background-color: red; padding: 5px">Warning!</p>
}

<!--
  Style binding
  In Angular, you would do that with [style.backgroundColor]="..."
-->
<p style="background-color: @Background; color=white; padding: 5px">Notification</p>

<!--
  Add/remove class
  In Angular, you would do that with [class.highlight]="..."
-->
<p class="note @((NoteIsActive ? "highlight" : ""))">This is a note</p>

<!--
  Bind to a collection
  In Angular, you would do that with *ngFor
-->
<ul>
  @foreach (var number in Numbers)
  {
    <li>@number</li>
  }
</ul>

Auch Two-Way Data Binding beherrscht Blazor bereits. Beispiele dafür findet man in Listing 3. Wenn man im C#-Code den Wert der gebundenen Variable verändert, ändert Blazor automatisch das UI. Umgekehrt werden Änderungen, die der Benutzer im UI macht, automatisch an die gebundenen Properties in C# weitergegeben. bind bindet standardmäßig an das Property value. Das passt gut für HTML input, select etc. Will man an ein Property mit einem anderen Namen binden (z. B. eines, das man selbst in einer Child Component definiert hat), verwendet man die Syntax bind-{PropertyName}.

What is your age? <input type="number" bind="Age" /><br />

@* Note how to pass a format for DateTime *@
What is your birthday (culture-invariant default format)? <input type="text" bind="Birthday" /><br />
What is your birthday (German date format)? <input type="text" bind="Birthday" format-value="dd.MM.yyyy" /><br />

@* Data binding for checkboxes with boolean properties *@
Are you an administrator? <input type="checkbox" bind="IsAdmin" /><br />

@* Data binding for selects with enums *@
<select id="select-box" bind="TypeOfEmployee">
    <option value=@EmployeeType.Employee>@EmployeeType.Employee.ToString()</option>
    <option value=@EmployeeType.Contractor>@EmployeeType.Contractor.ToString()</option>
    <option value=@EmployeeType.Intern>@EmployeeType.Intern.ToString()</option>
</select>

@functions {
  public enum EmployeeType { Employee, Contractor, Intern };
  public EmployeeType TypeOfEmployee { get; set; } = EmployeeType.Employee;

  public bool IsAdmin { get; set; } = true;
  public int Age { get; set; } = 33;
  public DateTime Birthday { get; set; } = DateTime.Today;
}

Routing

Blazor hat einen eingebauten Router (Microsoft.AspNetCore.Blazor.Routing.Router), der selbst wieder eine Blazor-Komponente ist, da er IComponent implementiert. Dieser Router darf nicht mit dem Router von ASP.NET Core verwechselt werden, da dieser serverseitig arbeitet. Der Router von Blazor läuft am Client. Wenn man auf einen Link klickt, der auf eine Komponente zeigt, die innerhalb der Blazor-App liegt, wird kein HTTP Request an den Server geschickt. Der Blazor-Router erledigt das auf dem Client.

Um eine Komponente unter einer bestimmten Route ansprechen zu können, verwendet man die Razor-Anweisung @page. Im C#-Code führt das dazu, dass der Komponentenklasse das Attribut Microsoft.AspNetCore.Blazor.Components.RouteAttribute hinzugefügt wird. Schreibt man eine Klasse ohne Razor nur in C#, muss man dieses Attribut selbst über die Klassendefinition schreiben. Eine Komponente kann bei Bedarf auch mehrere @page-Anweisungen bzw. Route-Attribute enthalten.

Variable Teile des Route-Templates schreibt man in geschweiften Klammern (z. B. @page „hello-planet/{Planet}). Der Router überträgt den Wert der Route-Template-Variable in eine gleichnamige Property. In Abbildung 5 findet man ein Beispiel, das dieses Konzept veranschaulicht. Rechts sieht man das Razor-Template mit @page und links den generierten Code mit dem Route-Attribut.

Abb. 5: Blazor-Router

Links werden bei Blazor mit dem normalen Anchor-Tag definiert (z. B. <a href=“/hello-planet/Epsilon-Eridani“>…</a>). Die Links dürfen keinen Servernamen enthalten. Blazor erkennt anhand eines base-Tags in index.html (standardmäßig <base href=“/“ />), welche Links relativ innerhalb der Blazor-App sind und welche auf externe Ressourcen verwenden. Die Links innerhalb der App verarbeitet der Router selbst, alle anderen werden normal vom Browser abgearbeitet.

In der Praxis hat man oft die Anforderung, programmatisch auf den Router zuzugreifen. Beispiele dafür wären Navigation vom Code aus statt über ein Anchor-Tag oder der Zugriff auf URL-Parameter. In solchen Fällen holt man sich über Dependency Injection ein Microsoft.AspNetCore.Blazor.Services.IUriHelper-Objekt. Es enthält zum Beispiel die Methode NavigateTo, um aus C#-Code heraus auf eine andere Blazor Page zu wechseln.

Dependency Injection

Blazor hat wie ASP.NET Core am Server ein Dependency-Injection-(DI-)System eingebaut. In der Main-Methode in Listing 1war schon zu sehen, wie man Services veröffentlichen kann. Injizieren kann man solche veröffentlichten Services mit der Razor-Anwendung @inject. Abbildung 6 stellt den Zusammenhang grafisch dar. Im Hintergrund wird durch @inject eine Property angelegt (in Abb. 6 wäre das die Property Repository), der beim Instanziieren der Komponente der entsprechende Wert zugewiesen wird.

Abb. 6: Dependency Injection in Blazor

Serviceimplementierungen (z. B. die Klasse Repository in Abb. 6) können ebenfalls auf veröffentlichte Services zugreifen. Dort muss man jedoch Constructor Injection verwenden, da diese Klassen keine Blazor-Komponenten sind und daher @inject nicht zur Verfügung steht.

Blazor bietet im Moment zwei Standardservices an, die zur Verfügung stehen, ohne dass man sie explizit über DI veröffentlichen muss:

  • IUriHelper: Dieser Service wurde bereits im Abschnitt Routing erwähnt. Er bietet Funktionen zum programmatischen Zugriff auf den Blazor Router an.
  • HttpClient: In Blazor-Apps kann man die gewohnte Klasse System.Net.Http.HttpClient zum Zugriff auf Web-APIs verwenden. Würde man sich einfach eine Instanz der Klasse selbst anlegen, könnte diese nicht auf das Netzwerk zugreifen. Wegen der Browser-Sandbox muss jeder Netzwerkzugriff über den Browser erfolgen. Blazor bietet daher über DI eine Instanz von HttpClient an, die im Hintergrund den Browser für HTTP Requests verwendet.

Layouts

Fast jede Web-App, die aus mehreren Seiten besteht, muss gewisse Layoutelemente wie Copyrighthinweis, Menüs, Logos etc. auf allen Seiten darstellen. Damit der entsprechende Code nicht manuell kopiert werden muss, enthält Blazor sogenannte Layouts.

Technisch gesehen ist ein Layout eine normale Blazor-Komponente. Sie enthält ein Razor-Template, kann C#-Code beinhalten, unterstützt DI etc. Die Komponente wird zu einem Layout, indem sie das Interface ILayoutComponent implementiert und die Razor-Anweisung @Body enthält. Dort, wo @Body steht, wird Blazor den Inhalt der jeweiligen Razor-Komponente einfügen, die über das Layout formatiert wird. Listing 4 zeigt ein Beispiel für ein Blazor-Layout.

 
@implements ILayoutComponent

<header>
  <h1>ERP Master 3000</h1>
</header>

<nav>
  <a href="/master-data">Master Data Management</a>
  <a href="/invoicing">Invoicing</a>
  <a href="/accounting">Accounting</a>
</nav>

@Body

<footer>
  © by @CopyrightMessage
</footer>

@functions {
  public string CopyrightMessage { get; set; }
  public RenderFragment Body { get; set; }
  ...
}

Um ein Layout in einer Blazor-Komponente anzuwenden, verwendet man die Razor-Anweisung @layout.

Parallele Programmierung

Eine wichtige Einschränkung von Blazor ist, dass parallele Programmierung mit Threads momentan nicht möglich ist. Im Augenblick läuft der C#-Code von Blazor im UI-Thread des Browsers. Natürlich wäre es wünschenswert, wenn aufwendige Rechenschritte in Hintergrundprozesse ausgelagert werden könnten. In zukünftigen Versionen von Blazor könnten dafür die Web Worker verwendet werden, die moderne Browser mittlerweile unterstützen. Das ist aber noch Zukunftsmusik.

Parallele Programmierung darf in diesem Zusammenhang nicht mit asynchroner Programmierung verwechselt werden. Diese wird bereits jetzt in Blazor unterstützt. Tasks, async/await, Timer – alle diese Funktionen stehen wie gewohnt in C# zur Verfügung und sollten auch genutzt werden.

Zusammenfassung und Fazit

Wie man in diesem Artikel sieht, bietet Blazor schon jetzt einen beachtlichen Funktionsumfang. Ich persönlich bin von dem Ansatz begeistert und hoffe, dass Blazor vielen .NET-Entwicklungsteams eine Zukunftsperspektive für ein UI im Browser bietet, die einfacher zu erreichen ist als ein Wechsel in die Welt von JavaScript, TypeScript, Angular, React & Co.

Wer mit SPA-Frameworks wie Angular bereits vertraut ist, dem fällt der Einstieg in Blazor noch leichter. Viele Konzepte erkennt man wieder. Bei aller Begeisterung für Blazor muss man aber zugeben, dass das Projekt erst am Anfang steht und bei Weitem nicht den Funktionsreichtum und die Stabilität eines Frameworks wie Angular bieten kann.

Ich hoffe, der Artikel hat Lust auf mehr gemacht. Wer mehr über Blazor erfahren will, dem empfehle ich als Erstes die vor Kurzem veröffentlichte offizielle Webseite https://blazor.net. Die Dokumentation ist noch überschaubar, Microsoft arbeitet gemeinsam mit der Community aber laufend an der Verbesserung. Ich habe vor einigen Monaten die Webseite https://learn-blazor.com gestartet, deren Hauptzweck die Überbrückung der Zeit bis zum Erscheinen der offiziellen Dokumentation war. Im Moment enthält meine Seite einige Informationen, die auf der offiziellen Webseite von Blazor noch fehlen. Das wird sich in den nächsten Monaten hoffentlich ändern. Wer im Moment eine Antwort auf eine Blazor-Frage sucht, sollte also auf beiden Seiten stöbern.

Blazor ist voll und ganz ein Open-Source-Projekt. Das Microsoft-Team ist dankbar für Feedback, Fehlermeldungen und Beiträge über GitHub. Wer also tiefer einsteigt und etwas zur Weiterentwicklung von Blazor beitragen möchte, kann das auf GitHub tun.

Unsere Redaktion empfiehlt:

Relevante Beiträge

Hinterlasse einen Kommentar

Hinterlasse den ersten Kommentar!

avatar
400
  Subscribe  
Benachrichtige mich zu:
X
- Gib Deinen Standort ein -
- or -