• WebAssembly ist eine neue clientseitige Technologie, die eine nahezu native Leistung ohne Plug-Ins in allen modernen Browsern, einschließlich mobiler Geräte, ermöglicht.
  • Viele Sprachen, darunter C, C#, Go und Rust, können Code kompilieren, der auf die stapelbasierte virtuelle Maschine WebAssembly abzielt.
  • WebAssembly ermöglicht die Ausführung von .NET-Code buchstäblich überall, auch im Browser.
  • Blazor ist eine clientseitige Bibliothek, die .NET auf WebAssembly verwendet, um in C# geschriebene Single Page Applikationen unter Verwendung von Razor-Templates zu unterstützen.
  • Blazor ermöglicht die Wiederverwendung von Code und die Fähigkeit, Legacy-Code in moderne Webanwendungen zu portieren.
WebAssembly Blazor

Mitte April 2019 stieß Microsoft sanft ein junges Framework aus der „Anything is possible“ Experimentierphase in eine „we`re committed to making this happen“-Preview. Das Framework, das den Namen Blazor trägt, weil es im Browser läuft und ein Templating-System oder eine „View Engine“ mit der Bezeichnung Razor nutzt, ermöglicht es den Entwicklern des Szenarions .NET, das sie fast aufgegeben hätten. Es erlaubt Entwicklern nicht nur die Erstellung von clientseitigen Code mit C# (kein JavaScript erforderlich), sondern auch die Ausführung vorhandener .NET-Standard-DLLs im Browser ohne ein Plugin.

Die Hoffnung Silverlight.

Der Traum von der Ausführung von .NET überall begann 2006 mit einem Application-Framework mit dem Codenamen „Windows Presentation Foundation/Everywhere (WPF/E)“, der als Silverlight der Öffentlichkeit vorgestellt wurde. Die erste Version unterstützte die deklarative Benutzeroberfläche, die der Welt über WPF unter dem Namen „Extensible Application Markup Language“ (XAML) vorgestellt wurde. Die Plattform bot feinkörnige Kontrolle über die UI-Elemente und stellte ein eigenes Document Object Model (DOM) bereit, das über JavaScript zugänglich war.

Die Einführung wurde beschleunigt, als Silverlight 2 im Jahr 2008 mit vollem Support für .NET über eine Common Language Runtime (CLR)-Implementierung, die als Browser Plug-In ausgeführt wurde, veröffentlicht wurde. Entwickler konnten jede .NET-Sprache zur Erstellung ihrer Webanwendungen verwenden, ausgereifte Datenbindungsmuster wie Model-View-ViewModel (MVVM) nutzen und mit Web-APIs über REST oder einen Windows Communication Foundation (WCF)-Client kommunizieren. Es sah langsam so aus, als könnten die .NET-Entwickler den JavaScript-Dust von ihren Füßen schütteln, sich keine Sorgen mehr über Cross-Browser-Tests machen und sich auf eine Plattform mit einer gemeinsamen Code-Basis konzentrieren, um ihre Anwendungen bereitzustellen.

Ungeachtet der Silverlight-Entwickler war das Jahr 2007 ein hartes Jahr für die Plattform. Zwei scheinbar nicht zusammenhängende Ereignisse traten ein, die letztlich zu ihrem Untergang führten. Erstens begann eine Zusammenarbeit zwischen der Web Hypertext Application Technology Working Group (WHATWG) und dem World Wide Web Consortium (W3C) mit der Arbeit am ersten Entwurf der HTML5-Spezifikation, die 2008 veröffentlicht werden sollte.

Das Rennen war im Gange. Smartphones entwickelten sich fast über Nacht von Flip-Phones mit Kontaktlisten zu tragbaren Computern mit Spielen und eingebauten Webbrowsern. Für eine kurze Zeit schien die Zukunft von Silverlight vielversprechend zu sein. Microsofts Antwort auf das iPhone, das Windows Phone 7, unterstützte eine Vorliebe für Silverlight als Entwicklungsplattform. Der Support von Chrome war im Kommen. Wenn Microsoft einen Weg finden würde, Silverlight auf iPhones und Android-Smartphones zu bringen, würde man endlich den heiligen Gral des „write once, run everywhere“ entdecken.

Nur war es nicht so.

Aus vielen Gründen, einschließlich der Sicherheitsbedenken beim Betrieb einer „virtuellen Maschine im Browser“, und der potentielle Batterieverbrauch, die Tür zu Browser-Plug-Ins, insbesondere bei mobilen Geräten, wurde eingestellt. Die Industrie begann, sich auf das Versprechen von HTML5 für den Aufbau mobiler Erfahrungen zu verlassen. Microsoft verlagerte seinen eigenen Fokus und als Silverlight 5 im Jahr 2011 veröffentlicht wurde, sagen die meisten Entwickler schon das Ende: Es würde keine neueren Versionen mehr geben.

HTML5 und JavaScript eroberten weiterhin die Herzen und Köpfe der Webentwickler. Werkzeuge wie jQuery normalisierten das DOM und erleichterten die Erstellung von Multi-Browser-Anwendungen, während gleichzeitig die Browser-Engines begannen, einen gemeinsamen DOM-Standard zu übernehmen, um die Erstellung einmal zu erleichtern und überall laufen zu lassen. Eine Explosion von Front-End-Frameworks wie Angular, React und Vue.js brachte Single Page Applications (SPA) in den Mainstream und zementierte JavaScript als die Sprache der Wahl für das Browser-Betriebssystem.

JavaScript als Plattform.

Im März 2013 wurde asm.js der Welt vorgestellt. Die Dokumentation beschreibt es als eine strikte Untermenge von JavaScript, die als effiziente Low-Level-Target-Language für Compiler verwendet werden kann. Die Spezifikation definiert im Wesentlichen eine Reihe von JavaScript-Konventionen, die es ermöglichen, den Code durch vorzeitige Kompilierung zu optimieren und bietet eine strikte Typisierung (JavaScript selbst ist eine dynamische Sprache) und ein Heap-basiertes Speichermodell.

Die Einführung von asm.js eröffnete einen neuen Bereich von Möglichkeiten, indem sie die Kompilierung von C/C++-Code zu JavaScript ermöglicht. Die Einschränkungen der Konventionen ermöglichten „asm.js Aware“-Engines die effiziente Kompilierung von JavaScript zu hoch performantem nativem Code. Um besser zu verstehen, wie dies möglich ist, betrachten Sie das folgende C-Codesnippet:

Copy to Clipboard

Der Code scannt eine Zeichenkette effektiv nach einem Testzeichen oder Null-Byte, das ihr Ende markiert und berechnet den Offset. C++ kann bereits mit einem Werkzeug mit der Bezeichnung Clang to byte code kompiliert werden, das mit der LLVM-Werkzeugkette konform ist. LLVM bezeichnet eine Reihe von Technologien, die eine schnelle plattformübergreifende Kompilierung von Code ermöglichen. Ein Projekt mit der Bezeichnung Emscripten nutzt die Werkzeugkette, um asm.js zu erzeugen.

Die Kompilierung des C++-Codes mit Emscripten erzeugt Dutzende von Zeilen hochoptimierten JavaScript. Der folgende Code wurde vereinfacht, um zu veranschaulichen, was generiert wurde:

Copy to Clipboard

Das generierte JavaScript ist mit allen Browsern kompatibel und läuft in allen Browsern einwandfrei. Die Exklusiv- oder mit Null-Operation (|0) macht aus jeder Zahl einfach eine vorzeichenbehaftete ganze Zahl. In älteren Browsern stellt dies sicher, dass die Zahl keinen Bruchteil enthält. In modernen Browsern informiert die Konvention den vorausgehenden Compiler, 32-Bit-Ganzzahlen zu verwenden (was zu schnelleren mathematischen Operationen führt), statt der standardmäßigen 64-Bit-Fließkommazahlen. Die Rechts-Verschiebung von Null (>>0) verhindert einen Überlauf und deklariert auch einen „Index“-Ganzzahl-Typ, der über HEAP8, einen typisierten Puffer von Bytes, der asm.js zur Verfügung gestellt wird, iteriert.

Es gibt keine for-Schleife, die in asm.js definiert ist. Alles wird in eine while(1)-Schleife übersetzt. Dies macht es einfacher, Compiler-Optimierungen anzuwenden. Die Optimierungen sind so effektiv, dass ein Team in der Lage war, die Unreal 4-Engine zu portieren, um 3D Ego-Spiele direkt im Webbrowser mit nahezu nativer Leistung auszuführen.

WebAssembly: Eine neue Hoffnung.

Schnellvorlauf bis 2017 und die Veröffentlichung von WebAssembly, einem binären Befehlsformat für eine stapelbasierte virtuelle Maschine. WebAssembly bietet ein portables Kompilierziel (kurz Wasm genannt), das gegenüber asm.js mehrere Vorteile hat:

  • Als Bytecode-Format muss das Skript nicht geparst und zur Optimierung vorkompiliert werden. Der Code kann direkt in native Anweisungen operationalisiert werden. Die Startzeiten zum Laden und Ausführen des Codes sind im Vergleich zu asm.js um Größenordnungen schneller.
  • Das Bytecode-Format ist eine kompaktere Art, Code zu liefern.
  • Wasm implementiert einen eigenen Befehlssatz und ist daher nicht durch die Sprache JavaScript eingeschränkt.

Jeder Code, der nach asm.js kompiliert, kann auf WebAssembly abzielen. Im vorherigen Beispiel wird durch eine einfache Änderung eines Compiler-Flags eine Datei mit der Erweiterung .wasm erzeugt. Die Datei ist nur 116 Bytes lang. Obwohl die Datei Bytecode enthält, gibt es eine standardisierte Textdarstellung des Codes, die als WebAssembly-Textformat bezeichnet wird. Dies ist die Textdarstellung des Suchmoduls in WebAssembly:

Copy to Clipboard

Der Code wurde auf die Größe optimiert, so dass die Funktion in a umbenannt wurde.

WebAssembly ist jetzt in einer stabilen 1.x-Version und wird von allen modernen Browsern, auch von mobilen Geräten, unterstützt. Mehrere Sprachen haben Wasm als gültiges Kompilierungsziel übernommen. Sie können WebAssembly-Programme mit C, C++, Go, Rust, TypeScript und Dutzenden anderer Sprachen erstellen. Es wurde in Lösungen für Computer Vision, Audio-Mixing, Video-Codec-Support, digitale Signalverarbeitung, medizinische Bildgebung, physikalische Simulationen, Verschlüsselung, Komprimierung und mehr implementiert.

Aber was ist mit C#?

Unmittelbar nach der Einführung von WebAssembly begann die Arbeit an der Portierung einer funktionierenden Version des .NET-Frameworks (einschließlich seiner Common Language Runtime), die auf WebAssembly ausgeführt werden soll.

Die Bemühungen waren erfolgreich.

Der Browser und die Razor View Engine.

Der Microsoft-Software-Ingenieur Steve Sanderson kündigte Blazor Ende 2017 in seinem persönlichen Blog an. Damals war es „nur ein Experiment“ und kein offizielles Produkt. Es begann mit der Frage: „Wie können wir .NET in WebAssembly zum Laufen bringen? Die erste Antwort war eine ältere, kompakte Version der .NET-Laufzeitumgebung, die er in wenigen Stunden als Wasm-Binary kompilieren konnte. .NET an sich ist im Browser nicht unglaublich nützlich: Sie benötigen eine Benutzeroberfläche und eine Möglichkeit zur Interaktion mit dem Nutzer. Aufbauend auf der stabilen Arbeit von Razor-Dateien, die Markup und C# zur Erstellung von Web-Templates kombinieren, fügte Blazor eine Reihe von Diensten hinzu, von der Datenbindung und der Injektion von Abhängigkeiten bis hin zur wiederverwendbaren Komponenten, Layouts und der Möglichkeit, JavaScript aufzurufen. All diese Dienste ermöglichen die Erstellung von Single Page Applications (SPA) unter Verwendung von .NET und C#.

Warum sollte sich jemand darum kümmern? Die ersten Reaktionen der Entwickler auf Blazor waren überwältigend positiv. Die Gründe dafür sind unter anderem die Folgenden:

  • Es ermöglicht Entwicklern, eine Sprache (C#) und ein Framework (.NET) zu verwenden, mit denen sie bereits vertraut sind, um clientseitige Anwendungen zu erstellen, die früher in JavaScript verankert werden.
  • Es läuft in allen modernen Browsern, auch in mobilen Browsern, ohne Plug-Ins.
  • Sie ermöglicht es Entwicklern, das .NET-Ökosystem zu nutzen und vorhandene Bibliotheken so zu verwenden, wie sie sind. Wenn Sie beispielsweise eine Blog-Engine mit Abschriften erstellen, können Sie das NuGet-Paket für eine vorhandene Markdown-Engine installieren und die Markups in HTML zur Vorschau direkt im Browser konvertieren.
  • Die .NET-Leistung hat sich im Laufe der Zeit weiter verbessert und ist daher mehr als ausreichend, um im Browser über Wasm zu laufen.
  • Blazor ist eine echte Single Page Application, die von einer Reihe statischer Assets aus läuft, die zu sehr niedrigen Kosten über Dienste wie statische Azure Storage-Webseiten gehostet werden können.

Nun, da Sie die Geschichte und die Motivation hinter Blazor kennen, lassen Sie uns einige der technischen Details untersuchen.

Alles, was Sie für die Installation von Blazor und den Start benötigen, finden Sie im Artikel „Erste Schritte mit Blazor“. Nach der Installation von Blazor können Sie wählen, ob Sie einen reinen Client oder einen Client mit ASP.NET Core-Backend -Projekt erstellen möchten. Das Projekt kommt bestehenden serverseitigen MVC-basierten Projekten auffallend bekannt vor. Die generierten DLLs werden jedoch direkt in den Browser geladen und von der WebAssembly-Version von .NET ausgeführt.

Das mono.js JavaScript lädt dynamisch mono.wasm und beginnt mit der Ausführung von .NET im Browser. Die verbleibenden Ladungen sind die eigentlichen DLL-Dateien, aus denen die Anwendung besteht.

C# im Browser (mit Dependency Injection).

Das Standardtemplate enthält eine Seite zum Abrufen von Wetterinformationen. Dies ist die Razor-Ansicht, die auf dem Client vollständig von Wasm gerendert wird.

Copy to Clipboard

Oben in dem Template bestimmen eine Reihe von Direktiven die Route der Seite, deklarieren eine using-Direktive und verwenden die Dependency Injection, um eine Kopie des HttpClients des .NET-Frameworks zu erhalten, die innerhalb des Browsers verwendet werden kann.

Copy to Clipboard

Schließlich wird ein Stück Code auf der Seite in einen @Funktionsblock eingebettet. Wichtig ist hier, dass der Code vollständig in C# vorliegt. Netzwerkoperationen können mit dem bekannten HttpClient durchgeführt werden und async/await werden unterstützt.

Copy to Clipboard

Das View Template stellt eine Seite dar, aber was ist mit den Steuerelementen?

Wiederverwendbare Komponenten.

Blazor basiert auf einer zusammensetzbaren UI aus hierarchischen Komponenten. Das einzige, was die Wettervorhersage-Komponente von jeder anderen unterscheidet, ist die Seitenanweisung, die eine Route bereitstellt. Hier ist das Template für eine Komponente mit der Bezeichnung LabelSlider.razor, die den eingebauten HTML-Eingabebereich um eine Spannweite erweitert, die den aktuellen Wert anzeigt.

Copy to Clipboard

Die Bindungssyntax ist im Format bind-{property}-{event}. Das Event ist optional und aktualisiert die Bindung immer dann, wenn das Event ausgelöst wird. Ohne dieses Event würde der Slider die Spannweite nur dann aktualisieren, wenn der Nutzer den Slider nicht mehr bewegt. Durch das Einhaken in oninput wird der Wert aktualisiert, wenn sich der Slider bewegt.

Der zugehörige Code stellt Parameter bereit, die es den übergeordneten Komponenten ermöglichen, den minimalen und maximalen Bereichswert und die Datenbindung auf den aktuellen Wert einzustellen. Die Action-Eigenschaft zeigt ein mit CurrentValue verknüpftes Event an und wird nach der Konvention CurrentValueChanged genannt, um eine bidirektionale Datenbindung zu erleichtern (übergeordnete Komponenten können auf geänderte Events „hören“ und gebundene Werte entsprechend aktualisieren).

Copy to Clipboard

Beachten Sie, dass Eigenschaften, die nicht mit dem Attribut Parameter gekennzeichnet sind, nur für die Komponente sichtbar sind. Die Wiederverwendung der Komponente ist so einfach wie das Einfügen eines Tags mit dem Komponentennamen und die Angabe der erforderlichen Parameter. Hier ist sie in Gebrauch:

Copy to Clipboard

In diesem Beispiel wird die Zweiwegbindung mit der aktuellenCount-Eigenschaft der übergeordneten Komponente hergestellt.

Vorhandene Bibliotheken verwenden.

Ein sehr mächtiger Vorteil von Blazor ist die Fähigkeit, bestehende Klassenbibliotheken zu integrieren, „wie sie sind“. Denken Sie zum Beispiel an eine Blog-Engine, die Markdown mit der Möglichkeit der Vorschau des generierten HTML im Browser verwendet. Dies in Blazor zu erstellen ist so einfach wie die Installation eines NuGet-Pakets, in diesem Fall des Open-Source-Prozessors MarkDig. Die Bibliothek kann anschließend direkt aufgerufen werden:

Copy to Clipboard

Die NuGet-DLL wird wie alle anderen Projektreferenzen in den Browser importiert und kann über die clientseitige Anwendung aufgerufen werden.

Aufruf an und von JavaScript.

Ein wichtiger Dienst, den Blazor anbietet, ist die Möglichkeit, JavaScript von .NET aus aufzurufen und umgekehrt. Alle JavaScript-Methoden, die Sie von Blazor aus aufrufen möchten, müssen vom globalen Windows-Objekt aus zugänglich sein. Um dies aufzurufen:

Copy to Clipboard

Die Interop-Funktionalität wird wie folgt genutzt:

Copy to Clipboard

Die Invoke-Async-Methode unterstützt die Übergabe und Rückgabe von Werten und die Werte werden automatisch in/von JavaScript/.NET konvertiert und von der Blazor-Laufzeitumgebung bereitgestellt. Verwenden Sie das JsInvokable-Attribut, um eine C#-Methode freizulegen, damit sie von JavaScript aus aufgerufen werden kann. Hier ist ein Beispiel, das den Aufruf der Markdown Conversion umgibt:

Copy to Clipboard

Rufen Sie von JavaScript aus DotNet.invokeMethod auf und übergeben Sie den Assembly-Namen, den Namen der exponierten Methode und beliebige Parameter.

Dadurch ist es möglich, Legacy-Anwendungen zu erweitern und bestehende JavaScript-Bibliotheken zu nutzen. Sie können sogar von Ihrer Blazor-Anwendung aus andere WebAssembly-Module aufrufen.

Blazor ist auf dem Vormarsch.

Microsoft hat Blazor aus der Experimentierphase in die offizielle Vorschau gebracht. Eine Version von Blazor, die das Komponentenmodell für das serverseitige Rendering verwendet, wird mit der endgültigen Version von .NET Core 3 ausgeliefert und die Client-Version wird kurz danach folgen. Es gibt noch viel Arbeit zu erledigen. Die Debug-Erfahrung ist extrem begrenzt und muss verbessert werden. Es besteht die Möglichkeit, die Code-Performance durch die Generierung von nativem Wasm mit vorzeitiger Kompilierung zu optimieren. Die Gesamtgröße muss reduziert werden, indem unbenutzer Code aus den Bibliotheken vor dem Versand and den Browser rasiert wird (ein Prozess, der als „Three-Shaking“ bekannt ist). Das Interesse und die Akzeptanz von WebAssembly wächst jeden Tag und mit Blazor wird der Traum, C# und .NET-Code zu schreiben, der buchstäblich überall laufen kann, endlich verwirklicht.

Vielen Dank für Ihren Besuch.