09.12.2020 | 

Webinar: Blazor WebAssembly: Neues in .NET 5

Ähnlich wie bei Angular und React wird auch bei Blazor ständig an der Plattform weiter gearbeitet. Vor allem bei Blazor WebAssembly als relativer Framework-Neuling sind die Verbesserungen und Neuerungen des ASP.NET-Teams bei Microsoft von Interesse.

In diesem Webinar zeigte Christian Weyer am 09. Dezember 2020 auf gewohnt pragmatische Art, was alles neu ist im .NET-5- Release und wie diese Features einzuordnen sind.

Mehr Beiträge zu ASP.NET Core, Blazor, SPA, WebAssembly
Christian Weyer ist Mitbegründer und CTO von Thinktecture. Er ist seit mehr als zwei Jahrzehnten in der Softwarebranche aktiv.

Moderation

Marco Frodl

Marco Frodl

Marco Frodl ist Consultant bei der Thinktecture AG und versteht sich als ein IT-Dolmetscher zwischen Developern und Anwendern.

Agenda

  • Maßnahmen für bessere Laufzeit-Performance
  • Verbesserungen beim Komponentenmodell
  • Developer-Tooling
  • Q&A

Material & Video zu
"Blazor WebAssembly: Neues in .NET 5"

Blazor WebAssembly: Neues in .NET 5 (Webinar vom 09.12.2020)

Es gibt Neuigkeiten zu Blazor im Zusammenhang mit .NET 5. Und dafür habe ich mir heute den Christian eingeladen, der jetzt hoffentlich wieder komplett online ist. Hi Christian!

Hi Marco! Vielleicht mal ganz kurz für die Teilnehmer da draußen. Wir haben ja 10 Sekunden vorher über dieses Thema gesprochen: Bei mir draußen steht ein Bagger irgendwo hier in der Straße. Ist kein Witz. Und gestern war das DSL schon zweimal weg. Und jetzt eben war es wieder weg, das DSL. Ich wohne ja auf dem Land und da ist das DSL natürlich ein hohes Gut. Jetzt bin ich aber geswitcht auf LTE. Und die Telekom hat hier ein 100 Gigabyte Weihnachtsgeschenk den Telekom Kunden zur Verfügung gestellt. Das heißt, ich bin jetzt komplett auf LTE. Da ist der Upstream aber nicht so gut wie bei DSL. Also nur, um mal die Expectations klar zu formulieren. Ich hoffe mal - drückt mir bitte alle da draußen die Daumen -, dass das Webinar mit LTE auch funktioniert.

Genau deswegen ist es vielleicht ganz gut, dass ich kurz etwas erkläre: Ihr könnt jederzeit im Chat rufen, wenn irgendetwas für euch nicht funktioniert. Wir zeichnen das Webinar ansonsten auch auf, so dass die Hoffnung besteht, dass im Nachgang des Video dann wenigstens auch alle Momente zeigt, die möglicherweise unterwegs im Paket-Strom untergegangen sind.

Wenn ihr Fragen habt, könnt ihr die in den Q&A-Tab stellen. Das hat den Vorteil, dass die anderen Teilnehmer voten können, welche Frage für sie auch relevant ist und wir nachher nach dem Webinar im Q&A-Teil dann natürlich auf die Fragen eingehen, die ganz, ganz oben stehen.

Und für alle die, die sagen "Ah, Moment, ich traue mich nicht, da eine Frage reinzuschreiben, wenn alle gucken", da haben wir heute eine Besonderheit. Die werden wir zum Schluss ankündigen. Es gibt also ein kleines Goodie für alle die, die diese Fragen haben, aber nie zu fragen wagten.

Also was der Marco eigentlich sagen wollte, ist, falls das Thema so sch*** langweilig ist und euch einfach nicht interessiert, bleibt wenigstens bis zum Ende drinnen, weil danach gibt's eine kleine Neuigkeit.

Und damit habt ihr schon alle Funktionen der Webinaroberfläche kennengelernt. Ich sehe schon, ihr schreibt uns ja zurück, dass ihr uns alle sehen könnt. Wir freuen uns auf jeden Fall, dass so viele in der Vorweihnachtszeit hier auch den Weg zu uns gefunden haben und dem Lockdown damit trotzen. Und damit würde ich schon sagen: Bühne frei, Christian, was gibt es denn neues bei Blazor im Bereich Performance und Footprint an Funktionen?

Jetzt hast du mir ja schon fast die ganze Story vorweggenommen. Vielen Dank, Marco, für die warmen Worte und vor allem für das Überbrücken während der Netzwerkprobleme. Also hallo, wunderschönen guten Morgen auch von meiner Seite aus. Ich bin der Christian von Thinktecture. Mitgründer und CTO meines Zeichens. Wunderschönen guten Morgen aus Unterfranken, aus Neustadt am Main. Ja, genau so trübe und genauso grau wahrscheinlich wie bei euch auch in den meisten Teilen der Republik oder auch in Deutschland und in Österreich, wo wir auch immer sehr viele Zuschauer und Zuschauerinnen haben.

Es freut mich immer ganz besonders, dass wir sozusagen ein ganz D-A-CH mittlerweile gesehen werden. Heut soll's gehen, um das Thema Blazor WebAssembly. Das ist so im Frontend mein Steckenpferd, mein Thema seid eigentlich zweieinhalb Jahren mittlerweile schon. Und möchte heute den Fokus legen auf die Neuerungen, die es gibt in .NET 5.

Wenn ihr Fragen habt zu diesem Webinar, zu diesem Vortrag, wenn ihr Fragen habt zu den ganzen Themen, die ich darin behandle, wenn ihr Fragen habt zu den Beispielen, die ich zeigen werde und die nicht jetzt stellen wollt, dann nachher in der Q&A oder auch mit dem neuen Angebot, was wir euch dann nachher vorstellen wollen. Ihr könnt mir natürlich auch immer eine E-Mail schicken an christian.weyer@thinktecture.com.

Wenn euch diese Webinare - dieses jetzt hier im Speziellen oder allgemein auch die Webinare von meinen ganzen Kollegen -, wenn die euch gefallen, dann schreit es auch gerne raus in die Welt über Twitter @christianweyer oder auch @thinktecture. So ein bisschen ja, ich sag mal Weiterempfehlung kann mit Sicherheit nicht schaden. Vielleicht könnt ihr ja auch ein paar Leute, die das noch nicht kennen, aber vielleicht auch daran Interesse zeigen könnten.

Das Webinar hier ist jetzt keine Einführung in Blazor WebAssembly. Da habe ich ja schon mal ein Webinar gemacht; im Januar. Ich werde auch nächstes Jahr natürlich wieder welche machen für all diejenigen, die sich eben noch nicht mit Blazor und vor allem mit WebAssembly auseinandergesetzt haben. Aber es gibt auch ein Recording und dieses Recording könnt ihr hier bei uns auf der Webseite runterladen. Das ist wie gesagt aus dem Juli und zeigt so die Basics anhand von ja so typischen Single Page Application Szenarien.

Gut, um was geht's? Der Marco hat es ja schon ein bisschen angedeutet und schon so ein bisschen geteasert: Erstmal gucken wir uns an, wie man überhaupt von .NET 3.1 von Blazor WebAssembly 3.2 hinkommen nach .NET 5. Wir werden uns ein bisschen unterhalten zu der ganzen Thematik um das Developer Tooling. Weil da gibt's ja doch durchaus Schmerzen und noch einiges nachzuholen vonseiten Microsoft.

Wir schauen vor allem auf Performancethemen und wir schauen vor allem auch auf Verbesserungen im Blazor Komponenten Modell.

Deswegen hätte ich auch gleich mal eine Frage an euch, wenn ihr schon Blazor WebAssembly verwendet, habt ihr denn da schon Probleme mit der Performance? Dazu erscheint gleich eine Umfrage. Wir hoffen, dass da ein paar Antworten reinkommen.

Die Frage war: Habt ihr aktuell Performanceprobleme in euren Blazor WebAssembly Anwendungen? Die Antwortoption "Ja". Die Antwortoption "Nein". Die Antwortoption "Wir setzen Blazor WASM noch nicht ein". Das ist übrigens die größte Gruppe. Und "Ja", haben ein paar Zuschauer ausgewählt, aber relativ wenige im Vergleich zu den zu den insgesamt abgegebenen Antworten. Das reicht mir auch schon, um einen ersten Eindruck dann zu bekommen. Und am Ende, wie gesagt und angedeutet, dann der ganze Q&A-Teil.

Blazor WebAssembly ist ja noch relativ jung - und ich vermute mal, das ist auch der Grund, warum viele hier in diesem Webinar und auch sonst in Gesprächen, die ich führe und auch auf anderen Konferenzvorträgen online bekomme -, warum viele Leute einfach noch ein bisschen warten. Es ist eine typische Version 1, so eine typische "Ja okay, wir haben jetzt was Neues", vor allem im Bereich Tooling, vor allem im Bereich Performance. Es sind coole Ideen dabei. Es fühlt sich teilweise richtig geil an, so dieses C# und .NET mit Intellisense, End-to-End programmieren und dennoch eine Single Page Application bauen, die dann eben in allen Browsern laufen kann. Aber es fehlt auch noch ein bisschen was.

Deswegen waren viele Leute auch sehr, sehr vorsichtig und abwartend und haben vor allem auf .NET 5 gewartet. .NET 5 wie alle anderen weiteren großen .NET Releases kommen ja jetzt im Jahresrhythmus.

Also .NET 5 kam jetzt im November 2020, .NET 6 wird im November 2021 kommen und so weiter und so fort. Und Microsoft und das Blazor Team ist da relativ offen bzw. sehr offen und veröffentlicht auch immer die jeweiligen Roadmaps, wie wir nachher noch sehen werden, und versucht also über eine agile Vorgehensweise auch an der Öffentlichkeit und mit der Öffentlichkeit zu kommunizieren und zusammen zu arbeiten, um eben dieses Framework weiterzutreiben.

Der Link, den ihr hier seht, das ist die offizielle Dokumentation zu den neuen Features von .NET 5. Und ich nenne es einfach mal eine Evolution, also eine Evolution anstatt einer Revolution. Das erinnert mich eigentlich so ein bisschen an das, was ich vor fünf, fünfeinhalb Jahren kennengelernt habe mit Angular. Also der Schritt vom AngularJS hin zu Angular 2 und natürlich dann auch alle nachfolgenden Varianten und Versionen. Da hat sich das so ähnlich angefühlt.

Das heißt, eine Entwicklung in der Öffentlichkeit als Open-Source-Projekt zusammen mit der sich gerade entwickelnden Community oder der eben schon teilweise existierenden Community. Also auch im Featureset, wie zum Beispiel bei der Anwendungsgröße - meine Güte, wie groß war eine Angular 2-Anwendung am Anfang. Das ganze Thema Packaging, klein bringen, verteilen. Das ganze Thema Performance, Change Detection, Optimierung et cetera pp. Das seh ich jetzt teilweise alles wirklich 1:1 wieder bei Blazor WebAssembly.

Das heißt natürlich, dass Blazor WebAssembly auch um eben genau diese Erfahrungswerte und vielleicht auch diese Jahre vor allem hinter Angular entsprechend hinterherhinkt, was man natürlich auch nicht vergessen darf, wenn man es als mögliche Alternative für sein nächstes Projekt oder für sein neues Vorhaben vielleicht in Betracht zieht.

Das ist so eine Liste aller Features, die eben extrahiert wurde aus dem gerade gezeigten Link. Ich will da überhaupt nicht großartig darauf eingehen, sondern will euch nur mal so ein bisschen eine Idee geben, über was wir hier auch sprechen werden und was ich euch zeigen möchte. Es sind also vor allem diese Themenblöcke Tooling, Performanceimprovements und Erweiterungen und Verbesserungen beim Komponentenmodell und beim Bauen und beim Nutzen von Komponenten.

Migration - also wie schaut es eigentlich aus? Wie komme ich jetzt von der .NET Core und von einer Blazor WebAssembly 3.2. zu .NET 5? Kompatibilitätsmäßig schaut es so aus: Es gibt relativ wenige Breaking Changes. Am Ende von der Präsentation, am Ende der Folien habe ich eine ganze Liste an URLs, Referenzen und an Verweisen, wo ich euch dann auch jeweils zeige, was ich hier erwähne. Und da ist auch der Link zu der Kompatibilitäts- bzw. Breaking Changes-Auflistung drin.

Es sind relativ wenig Breaking Changes. Es hängt natürlich immer davon ab, in welchem Umfang man welche Features verwendet. Aber ich habe einem Kundenprojekt geholfen umzustellen und wir haben auch ein paar interne Proof-of-Concepts-Apps umgebaut. Es ging relativ schnell. Und wenn man mit seiner .NET 3.1-Anwendung rüberschwingen möchte in die neue .NET-Welt, dann geht das eigentlich relativ einfach.

Ich versuche euch das einmal hier live zu zeigen. Am offenen Herzen quasi - Operation am offenen Herzen. Wir müssen zuerst die SDK Version updaten. Dafür gehen wir in das Projectfile. Und in dem Projectfile müssen wir hier oben nun eben Blazor WebAssembly verwenden. Wir müssen außerdem die Target Framework Version hochschrauben und können tatsächlich die Razor Lang Version raushauen. Wir müssen hier überall auf die 5er Version hochgehen bei den Nuget Packages. Und müssen gucken, dass wir ein Package - nämlich dieses WebAssembly Build - rausschmeißen. Das ist schon einmal der Teil. Man sieht, er macht schon "Restoring Packages" da oben.

Was noch eine wichtige Änderung bei Blazor WebAssembly unter .NET5 ist: In der Anwendung selber hat man sich entschieden, dass man kein eigenes Element mehr hat, sondern dass man diesen App-Anker zu einem Div macht. Div-Id ist App. Und dann muss man auch die program.cs entsprechend umstellen. Das ist dann hier einfach so, dass wir uns auf dieses Div mit dieser Id beziehen. Und das war's eigentlich schon. Jetzt ist meine Anwendung bereits komplett eine .NET 5 Anwendung.

Wenn wir das gleich einmal starten, dann werden wir sehen, dass die Anwendung zwar startet, aber es schaut nicht so aus, wie man es kennt, weil hier unten das Layout anders ist. Das hat einen ganz einfachen Grund, nämlich vom vom Project Template Wizard in Visual Studio von .NET 3.1 zu .NET 5 hat sich das CSS geändert. Deswegen schaut es jetzt hier so zerrupft aus. Aber es gibt diesbezüglich keine Fehler. Wenn wir das ganze mit den Developer Tools anschauen, dann seht ihr hier auch: wir laden jetzt wirklich die dotnet.5.0.0.js und das .NET. ist jetzt auch wirklich dotnet.wasm und nicht mehr mono.wasm, weil wir mit der Version .NET 5 dann komplett auf das Unified Framework rüberswitchen.

Das heißt, um diese Anwendung jetzt wieder schön hinzubekommen, müsste ich jetzt halt noch einiges am CSS umbauen aber spare ich mir jetzt einfach mal. Das heißt, die Migration auf die neue Blazor WebAssembly-Version ist relativ simpel und relativ schmerzfrei.

Wie schaut es aber aus mit dem Developer Tools für Blazor WebAssembly? Was ist also mit Sachen wie Debugging? Das war ja bisher ein bisschen hakelig. Was ist mit Dingen wie Live Reloading oder sogar HMR, also Hot Module Reload? Da muss ich euch leider ein bisschen auf den Boden der Tatsachen zurückholen, wenn ihr jetzt schon ein bisschen geschwebt seid, weil da hat sich nicht viel getan. Es gibt zwar Debuggingverbesserungen, dass heißt das Debugging sowohl innerhalb von den Browsern als auch innerhalb von Visual Studio ist jetzt ein bisschen stabiler. Aber so richtig cool und so richtig geil - sag ich mal ganz unverblümt -, wie man es halt von normalen .NET-Anwendungen auf Desktop oder Serverside kennt -, ist es leider immer noch nicht.

Debugging funktioniert jetzt auch in Visual Studio for Mac, falls irgendjemand von euch macOS da draußen am Start hat, so wie hier. Aber ansonsten ist es ist leider noch nicht so viel damit passiert.

Was sie bei Microsoft reingebaut haben, ist ein sogenannter Compatibility Analyzer. Das heißt, wenn man Assemblies oder Nuget-Packages referenziert, die nicht innerhalb des Browsers ausführbar sind, also quasi eine unsupported Platform haben, dann bekommst man gleich entsprechende Fehler angezeigt im Visual Studio Build. Das heißt, wenn Microsoft z.B. im .NET Framework eine Klassenbibliothek hat, die eben schon diese diese Kompatibilitätsstufe unterstützt, z.B. weil du versuchst in deiner Blazor WebAssembly-Anwendung einen TCP-Socket aufzumachen oder ein UDP-Rendezvous zu implementieren, dann bekommst du sofort beim Kompilieren einen entsprechenden Fehler.

Reload als Entwicklungsfeature bei Blazor WebAssembly ist ein bisschen enthalten. Ich sage extra "ein bisschen", weil es echt ein bisschen verquer ist, nämlich über das Kommando "dotnet watch" und eben auch integriert in die allerneueste Version von Visual Studio 2019, nämlich die Version 16.8. Aber es funktioniert wirklich nur so halbgar und du musst immer wieder kompilieren und es ist eigentlich nicht wirklich ein Reload.

Da verwende ich und mittlerweile sehr viele andere Leute aus der Community und auch Kunden, die wir so betreuen, momentan einfach ein externes Tool. Das externe Tool heißt LiveSharp. Dieses LiveSharp will ich euch mal ganz kurz zeigen, indem wir hier einfach mal ein neues Projekt erzeugen.

Wir sagen hier "neue WebAssembly" und verwenden gleich die .NET 5 und bennen sie zum Beispiel "LiveSharpDemo". Und schauen uns jetzt mal an, was hier möglich ist. Das ist eine ganz normale Blazor WebAssembly-Anwendung und ich füge hier jetzt einfach mal schon ein Nuget Package hinzu. Das ist nämlich dieses LiveSharp. LiveSharp ist ein kommerzielles Produkt. Das muss man sich dann mal im Detail angucken - es ist auch verlinkt in den Folien -, ob einem das Preismodell soweit zusagt.

Ich bin momentan der Meinung, dass man sich das gönnen sollte, wenn man ernsthaft Blazor WebAssembly entwickelt. In der Hoffnung natürlich, dass dann z.B. innerhalb des Zeitraums bis zu .NET 6 oder spätestens mit .NET 6 Microsoft und das Visual Studio-Team dann den entsprechenden Live Reload auch wirklich umgesetzt bekommen. Ich habe gesehen, dass Steve Sanderson, dem Master-Architekt hinter Blazor und Blazor WebAssembly, dass er da gerade am Bauen und am Basteln ist. Das heißt also, das wird auf jeden Fall kommen.

So, und was ich hierfür noch brauche, ist das Package SignalR-Client. Was LiveSharp macht ist, du brauchst hintendran einen lokalen Server der monitored dir die Änderungen. Das heißt, was LiveSharp macht ist, du musst keinen Code jetzt da explizit irgendwo in deiner Anwendung oder in einer App einbauen, sondern es ist nur ein Build Task, was jetzt passiert ist. Wir bauen die Anwendung. Wir haben zwar hier jetzt ein neues File erzeugt bekommen, aber das ist wirklich nur optional, wenn man sich in den LiveSharp-Prozess integrieren möchte. Da gibt's dann so ein entsprechendes webbasierendes Dashboard und da kann man sich dann mit eigenem Code über das LiveSharp API integrieren.

Ich starte einfach mal die Anwendung und dann gucken wir mal, was passiert. Ich ziehe es mal hier rüber.

So, das ist jetzt unsere Anwendung. Und wir sehen hier unten, dass jetzt dieser LiveSharp Server das Dashboard geöffnet hat und hier bei uns in der Anwendung sehen wir LiveSharp Server connected. So, jetzt versuche ich mal, das irgendwie auf einen Bildschirm zu bringen und die einfach mal in die Index.razor und mache mal so diese typischen Sachen, die einfach gehen sollten, oder?

Textänderung "Hallo liebes TT-Webinar" und schon wird es aktualisiert. Das heißt also, diese Live Reload- und teilweise Hot Module Reload-Themen, die gehen. Die gehen auf Markup-Ebene und die gehen auch hier auf der Kompetenten-Ebene. Ich nehme diesen Survey-Komponentenaufruf jetzt einfach mal raus und speichere und zack, ist es aktualisiert. Es ist tatsächlich instant. Das heißt, das ist eigentlich schon sehr, sehr nahe an dem, was ich mir als Single Page Application Entwickler, der 2010 mit AngularJS angefangen hat, was ich mir eigentlich wünsche. Reload ist also momentan möglich, aber eben temporär vielleicht mit diesem Third-Party Produkt, weil es eben innerhalb von .NET auch mit .NET 5 noch nicht als Frameworkfeature da ist.

Was ist noch neu? Noch neu ist, dass die Anwendungsgröße kleiner geworden ist, weil in .NET 5 gibt es das sogenannte App-Trimming. App-Trimming ist es sowas ähnliches wie Tree Shaking, das man vielleicht aus anderen SPA Frameworks kennt.

In den Blazor WebAssembly-Templates und in den Build Tasks ist es automatisch angeschaltet. Man muss aber aufpassen: Wenn man z.B. sowas macht wie .NET-Reflection oder irgendwelche anderen dynamischen Code-Lademechanismen oder sogar Code-Erzeugunsmechanismen, die innerhalb von Blazor WebAssembly überhaupt funktionieren würden, dann kann das natürlich einen unangenehmen Seiteneffekt haben. Deswegen muss man es immer sehr, sehr stark und sehr, sehr früh entsprechend testen, ob dieser Application-Trimmer nicht einfach zu viel wegschmeißt.

Bei dem Standardtemplate hält es sich momentan in Grenzen. Also da passiert ja nicht viel, deswegen kann der App -Trimmer dann natürlich wunderbar einfach drüber rauschen und kann seine Optimierung machen. Es sind ein paar hundert Kilobyte, die da wegfallen und der App-Trimmer wird automatisch angetriggert, wenn ihr einen Release Build macht und das Paket published also mit "dotnet publish -c Release" erzeugt. In diesem Fall wird der App-Trimmer automatisch angestoßen und wird euer Bundle dann entsprechend kleiner machen.

Wenn ihr das nicht haben wollt, weil es natürlich auch Buildzeit kostet und ihr möchtet eure Anwendung öfter mal publishern z.B. über einen CI/CD Integration Build in einen Azure Blob Storage oder in eine Azure Web App, dann kann man das auch disablen über eine entsprechende Property in eurem C#-Projectfile.

Normalerweise habt ihr mit dem App-Trimmer nichts zu tun, außer eben wie erwähnt, wenn ihr Sachen am Start habt, die vielleicht mit dynamischem Code arbeiten, aber ansonsten sollte er euch eigentlich zugute kommen, weil das .NET-Team arbeitet auch immer weiter an der weiteren Optimierung des jeweiligen darunterliegenden Frameworks. Heute Nacht zum Beispiel kam .NET 5.0.1 heraus. Das heißt, mit jedem Patch und mit jeder neuen Version, die wir sehen werden auch auf dem Weg hin zu .NET 6 werden wir immer weitere Optimierungen sehen in der Application Size. Warum hat .NET das Feature überhaupt drin? Es hat nämlich gar nichts initial mit Blazor WebAssembly zu tun, sondern das ist ein .NET 5 Features für das Single File Deployment. Du kannst du ja jetzt in .NET 5 deine Anwendung komplett als Single File Application deployen. Ob das dein serverseitiger Service ist, ob das deine clientseitige WPF- oder Windows Forms-Anwendung ist. Daher kommt dieses Feature und steht eben auch für Blazor WebAssembly zur Verfügung.

Gut. Was ist mit der Performance? Also vor allem mit der Runtime Performance? Wir haben ja in unserem Webinar-Poll gesehen, dass 16 Prozent sagen, dass sie durchaus schon ein bisschen Performance Probleme haben. Lasst uns deshalb mal reinschauen, was es so an Neuigkeiten gibt!

Also eine Sache ist, dass das Blazor Team intern sehr stark daran gearbeitet hat, die Runtime einfach schneller zu bekommen. Konkretes Beispiel aus unserer Beratung: Ich habe einen Kunden, der hat ein relativ komplexes Third-Party-Modul und -Bundle verwendet für UI, welches Material-based ist. Und die haben mit .NET 3.1 angefangen und dann sind wir migriert auf .NET 5. Haben die notwendigen Anpassungen gemacht und man hat sofort gemerkt: es ist diese "perceived performance". Das heißt, wenn du da wirklich sofort rangehst und z.B. eine lange Liste lädst, dann hast du irgendwie gemerkt "Oh ja, das ist schon entsprechend schneller". Vielleicht kann ich das sogar einmal nachstellen. Ich probiere es einfach mal.

Ich habe hier eine Beispiel Anwendung, die eben jetzt so ein Third-Party Framework verwendet. Das ist jetzt hier MudBlazor und bei MudBlazor bin ich jetzt hier im .NET 3 Branch.

Ich starte den mal! Der müsste dann gleich hier entsprechend auftauchen. Jo!

So, ich hab hier natürlich jetzt die ganze Zeit ein paar Performanceeinbußen, schon allein wegen dem Live Streaming heute, das heißt so so richtig realworld-ig sind diese Daten wahrscheinlich nicht.

Aber - das ist schon extrem langsam heute. Aber okay, wir probieren es einmal. Das ist echt spannend. Wir gehen mal hin und gucken uns das mal an. Weil ich gebe hier aus auf der Konsole, wie lange das dauert. Und wir sehen hier unten hier in dem Bereich: es hat jetzt 3,4 Sekunden gedauert, diese Daten zu binden. Und ich sage euch, das hat auch mit diesem Streaming hier zu tun. Normalerweise in den Tests gestern und vorgestern war das immer so, bei einer Sekunde oder bei 1,5 höchstens okay.

Aber gut, wir wollen ja nur die relativen Zahlen sehen. Das ist jetzt .NET 3.1. Jetzt gehe ich rüber und switche mal den Branch. Und der Branch heißt hier "with-service-50". Ja!?

Wartet mal kurz.

Was hab ich denn hier an Working Changes? Ja, okay, alles klar. Da können wir uns eigentlich schenken. Gut. Jetzt hab ich den Branch geswitcht. Jetzt mache ich mal hier eine Stop.

Und versuche mal einen Rebuild anzustossen. Die Packages hat er successfull restored. Jetzt machen wir mal Rebuild. Sind beides Debug-Builds, übrigens. Ich versuche hier wirklich so einigermaßen Äpfel mit Äpfeln zu vergleichen. Ich habe jetzt nicht da drüben einen Debug- und hier jetzt einen Release-Build oder sowas gemacht.

Der Code ist wirklich absolut identisch. Ich habe nur die Runtime unten drunter ausgetauscht. Und wenn er sich mal hier begnügt, fertig zu werden.

Das dauert echt komisch lange. So machen wir hier mal ein "Start without Debugging".

Und schauen mal, dass er hier gleich hochkommt.

Kommt er?

Da kommt er.

Ja, die Maschine ist echt ziemlich am Ende, sehe ich gerade. Ist eben so ein typischer ...

Ja, das ist korrekt. Das ist die Krux bei Single Page Applications, wo Daten gecached werden.

So. Gut, also wir sind jetzt hier. Und switchen jetzt mal auf "Fetch data", das dauert immer noch verdammt lange. Aber wir werden jetzt sehen, dass wir natürlich jetzt hier unten wieder - ich sag mal - so ungefähr halb so lange nur brauchen und, dass glaubt ihr mir einfach: Wenn jetzt hier nicht irgendwie diese ganzen Streaming Sachen an sind, dann habe ich ungefähr einen Vergleich gehabt von 0,9 oder 1,1, 1,2 hin zu 0,3 Sekunden für das Rendering.

Das heißt also, da sieht man schon, dass die interne Runtime entsprechend optimiert wurde, vor allem wenn es darum geht, eben String Handling zu machen, Dictonary Handling zu machen und vor allem die JSON Serialisierung und Deserialisierung.

Weiterhin kann man sehen, dass diese Performanceoptimierungen on-going sind. Es gibt ein GitHub Projekt in dem offiziellen Repository. Das ist auch wieder hinten verlinkt in den Folien. Das könnt ihr euch auch mal anschauen in Ruhe. Wo man dann auch wirklich nachvollziehen kann, was wird wirklich wie getestet.

Und dann gibt's entsprechend das Power BI Dashboard dazu, was verlinkt wird, wo man dann auch die Entwicklung sieht, wie sich diese Runtimeperformance über die Zeit hin entwickelt.

Was kann man jetzt aber noch machen? Also wir haben ja in Blazor WebAssembly diese Problematik, dass wir eine relativ große App-Size und App-Bundle haben, was jetzt erst mal runtergeladen werden muss. Und dieses App-Bundel wird zwar jetzt über den App Trimmer zwar kleiner, aber am Ende des Tages dauert es halt je nachdem, ob ich z.B. eine schnelle oder eine langsame Verbindung habe oder ob ich mobil unterwegs bin, kann es natürlich entsprechend dauern und das ist natürlich eklig für den Benutzer. Dann sieht man oben bei einem Standardtemplate dieses "Loading ...". Ja, was irgendwie uncool ist.

Das wollen wir mal unter die Lupe nehmen: in .NET 5 gibt es dafür etwas, dass heißt, SSR in der SPA-Welt, also Server Side Rendering um eben den initialen Hook, den initialen - ich sage mal - Lade-Schluckauf, also Hickup nicht Hook, ich sage mal wegzubekommen.

Was da passiert, ist: ich muss meine Anwendung schon signifikant umbauen. Das kann ich euch jetzt auf Grund der Fülle der Themen oder von der zur Verfügung stehenden Zeit natürlich nicht live zeigen, habe aber eine entsprechende Demo vorbereitet. Wir schauen uns das gleich mal an!

Dafür gehen wir hier rein, machen einmal das hier auf. Was wir nämlich machen müssen, ist, wir müssen quasi so ein bisschen Blazor Server reinholen, aber keine Angst, wir machen kein Blazor Server.

Aber die Funktionalität zum pre-rendern auf dem Server ist ja schon da im Framework nämlich in Form von pre-rendering für Blazor Server. Und dafür müssen wir aber eben halt ein bisschen umbauen. Also eine Umbaumaßnahme ist z.B. im Client. Ihr seht, hier ist kein wwwroot-Folder mehr. Der wwwroot-Folder ist jetzt runtergezogen in den Server. Weil wir natürlich immer erst einmal pre-rendern auf dem Server. Ja. Und wir haben die index.html einfach gelöscht bzw. ich habe sie halt hier umbenannt, weil das Ganze jetzt vonstattengeht über den Server. So, dass heißt also, es ist ein gewisser Umbau notwendig, um dieses Server Side Rendering zu bekommen.

Das ist ein nicht zu vernachlässigender Grund, dass man darüber nachdenkt, weil vor allem wenn komplexere Szenarien am Spiel sind, zum Beispiel clientseitige Authentifizierung über OAuth und über OpenID Connect. Das kann ganz schön tricky werden. Und tatsächlich gibt's da wohl auch noch ein paar Ungereimtheiten in der aktuellen Implementierung von Pre-rendering.

Wie schaut es denn im Ablauf aus, wenn ich kein Pre-rendering mache? Ich komme gleich auf den Code wieder zurück. Im nicht pre-rendering Fall mache ich ja einen Request an meine URL z.B. hier "/Counter" aus dem berühmten Startertemplate. Dann bekomme ich die Indexseite zurück. Da drin sind die ganzen JavaScriptfiles zum Laden der Anwendung und der .NET Runtime. Es werden dann die Anwendungs-DLLs geladen. Dann wird mein "counter.razor gerendert, clientseitig und alle anderen weiteren Requests wie z.B. oben Daten anzuzeigen, die von einem API kommen, die passieren ja immer alle clientseitig, also Client ist dieser grüne Teil und der blaue Teil ist eben der Server. Und der Server ist einfach nur dumm, im Sinne von: er liefert halt einfach die Daten zurück, die ich angefordert habe.

Mit Pre-rendering schaut das Ganze natürlich signifikant anders aus.

Ich mache wieder einen Request auf diese Adresse "/Counter". Jetzt wird aber das ganze Server-side pre-rendered. Das heißt, der Code wird ausgeführt auf dem Server und wird dann als statisches HTML hier in diesem Schritt zurückgeliefert mit ein paar Metadaten drin, mit der sogenannten Pre-render ID.

Damit der Client dann später, wenn nämlich das HTML angezeigt wurde, wenn die .NET-Runtime geladen wurde, wenn die Anwendungs-DLLs geladen wurden, dann wird er interaktiv und dann kann er eben über diese Pre-rendering ID dies aus dem statischen HTML kann er dann sozusagen das Kommando übernehmen und wird dann von dem Zeitpunkt an zu einer echten Single Page Application.

Also es ist ein bisschen crazy und von da an hab ich ganz normal wieder die Interaktion wie ich es vorher auch hatte ohne Pre-rendering und kann dann z.B. meine API-Calls machen. Wie schaut es denn jetzt live aus? Also zum einen mal müssen wir die index.html ersetzen durch eine Server seitige _Host.cshtml und haben dann hier diesen WebAssemblyPrerendered-Mode drinnen für unsere für unsere App. Die App ist immer noch die clientseitige App. Ja? Das ist immer noch diese App.Razor - da hat sich nichts dran geändert.

Was wir machen müssen ist, in dem Startup vom Server: wir müssen sicherstellen, dass alle Dependencies und alle Konfigurationen, die wir im Client machen, also in der SPA, auch auf dem Server vorhanden sind. Deswegen habe ich das mal hier refactored. Habe quasi alle clientseitigen Services auf der IServiceCollection extrahiert in eine eigene Klasse, so dass ich sie dann clientseitig verwenden kann und eben auch serverseitig verwenden kann. Das heißt also, es ist schon einiges an Umdenken, Umbauen und vor allem viel, viel Testen notwendig.

Wenn ich das jetzt starte: Und er baut und er baut und er baut. Das ist jetzt der Nachteil von Webinaren. Normalerweise würde ich jetzt Fragen stellen in die Audience. Jetzt stelle ich einfach eine Frage in die Kamera: lieber Compiler, ahja, Build successful. Und jetzt warten wir mal bis hier die Anwendung startet. So. Man hat es wahrscheinlich überhaupt nicht so wirklich richtig erkannt, weil wir durch das Streaming natürlich auch einen entsprechenden Lag drinnen haben beim Rendering, aber im Endeffekt kann man sehen, dass wenn ich jetzt hier reloade:

Das ist immediate. Da ändert sich nichts. Da ist kein Loading. Punkt, Punkt, Punkt. Da ist gar nichts mehr, weil eben die serverseitige Kalkulation; der serverseitige Code ausgeführt wird, um dann als statisches HTML erst einmal zu uns runter zu kommen. Ja? Da! Und hier seht ihr auch diese Pre-render IDs, die eben Metadaten sind und notwendig sind, damit der Client, also die Client Runtime von Blazor dann im SPA-Fall wieder komplett übernehmen kann.

Ja, und dann, wenn eben diese Anwendung geladen wurde, dann kann ich wieder ganz normal herumklicken und dann habe ich auch wieder ganz normal meine SPA. Also ihr seht es ja hier. Wenn ich auf "Conferences" gehe, da wird ganz normal mein Conference API wieder aufgerufen und entsprechend verhält sich dann ganz normal wieder wie eine Single Page Application.

Zu Beginn ist es wirklich immediate; es ist wirklich instant, weil das Rendering das Ausführen des Codes des Pre-rendering auf dem Server wirklich sackschnell geht, um es mal so zu formulieren, dass ich dann eben diese diese "perceived waiting time", "loading time" für den Benutzer entsprechend minimieren kann. Ok.

Dann machen wir mal weiter im Text. Weiteres Performancethema. Da können wir auch noch nachher noch drüber reden Marco, aber wie oft haben wir das schon gehört? "Meine Anwendung ist langsam. Was ist das für eine Scheiß-Technologie?" Hunderte Male! Heftig, oder? Und zwar egal welche Technologie. Ob das Windows Forms war. Ob es dann später WPF war. Ob es AngularJS war. Ob es dann später Angular 2 war. Ob es jetzt WebAssembly ist oder Blazor - es ist völlig egal. Es ist immer das gleiche.

Ja, natürlich ist Blazor WebAssembly - ich sage mal - von Natur aus langsamer als z.B. ein React oder VueJS oder auch Angular, weil ja man aus WebAssembly heraus nicht nativ auf Document Object Model zugreifen kann, deswegen gibt's ja immer diese Interop-Brücke und deswegen ist es natürlich erst einmal so lange immer natürlicherweise langsam, bis man aus WebAssembly wirklich auch native auf den DOM zugreifen kann. Aber dennoch: es war einfach schon immer falsch, in jeglicher Anwendungsarchitektur, in jeglicher Technologie tausende von Datenreihen in den Client zu laden und sie irgendwie an ein Datagrid zu binden.

Das war schon immer falsch, weil niemand kam mit tausend Datensätzen visuell was anfangen. Das heißt, man kann sich schon 1.000 Daten laden in den Speicher, zeigt dann aber z.B. nur - weiß ich nicht - 10 oder 20 oder von mir aus 50 an und wenn man dann durchscrollt oder durchpaged, das kennt man ja. Ja, da gibt's ja so typische Patterns, wie man das dann irgendwie aufteilt, so Paging oder eben Endless Scrolling. Dann bindet man die Daten eben wieder neu, muss aber die alten DOM Elemente natürlich entsprechend wegschmeißen bzw. recyceln.

Das ist ein klassischer Use Case, dem man in jedem Single Page Application Framework begegnet, egal wie sie heißen. Und dafür hat es halt auch eine Notwendigkeit in Blazor WebAssembly. Eben auch, weil eben diese natürliche Performance eben nie so hoch sein kann, aktuell, wie bei den JavaScript-basierten Frameworks. Und da hat das Blazor-Team eine Komponente ins Spiel gebracht, die heißt Virtualize. Und Virtualize ist jetzt ein Feature, dass ich sag mal relativ einfach zu adopten ist. Es gibt zwei Ausprägungen, wie man es einsetzen kann.

Einmal: man lädt wirklich über ein API-Call z.B. alle Daten, hat die dann im Speicher und bindet das dann an diese Virtualize Komponente. Dies sorgt dann dafür, dass man wirklich immer nur die Daten bindet im Document Object Model, die man auch sieht. Ja, über den Viewport und über die Größe der jeweiligen angezeigten Zeile z.B. in einer Tabelle. Oder man macht sowas wie Paging schon beim Daten holen. So möchte ich es mal formulieren. Lasst uns das auch mal anschauen.

Auch hier hab ich eine Demo - Virtualization - und schauen uns das mal an! Sodele, also das ist wieder mehr oder weniger meine Standarddemo. Auf dem Server gibt es dann halt ein API. In diesem Fall ist es aber kein WebAPI oder ein API-Controller, sondern es ist ein gRPC-Service, wo ich dann streng typisiert über ein Interface Binärdaten austauschen kann und hole mir so z.B. die Liste von den Konferenzen, so.

Was wir jetzt hier haben auf dem Client sind zwei Implementierungen dieser Conferences Page: einmal hinter "/conferences", einmal hinter "/conferences-provider" und die eine ist relativ straightforward. Ich habe also immer noch eine Tabelle - wie ihr seht - und habe jetzt hier diese Virtualize Component drin und dafür kann ich einfache Datenbindung machen an das Objekt, so wie ich's bisher auch gemacht habe. Also hier ist nichts custom im Code. Ich rufe hier einfach nur meinen gRPC-Service auf. Das könnte wie gesagt auch WebApi-Call sein, um eben dann meine Daten zu bekommen.

Packe das hier in so eine Liste und zeige es hier einfach an. Gebe an, wie die Laufvariable heißen soll und mache hier entsprechende Datenbindung. Wenn ich mir das mal angucke: "Start Without Debugging"

So. Anwendung startet. Anwendung läuft. So. Was ich jetzt mal mache, ist, ich gehe schon mal gleich in den Inspektor und wir gucken uns das Ganze mal im Document Object Model an. Wir gehen mal hier auf Conferences In-Memory und schauen uns mal diese Liste hier an. Ist ja irgendwie. Na, wo ist sie? Da! So! Das ist die da. Dann haben wir hier die Tabelle. Mache es mal noch eins größer. Und dann haben wir hier den Body. Dann haben wir hier die Elemente.

So, und wenn ich jetzt hier durchscrolle, seht ihr schon rechts: Die Höhe verändert sich. Und das es hier lagged, ist wieder das Streaming. Das ist lokal absolut smooth. Das heißt, was hier passiert ist: Ich habe, ich glaube 300 Einträge oder sowas? Ja? Und wenn wir mal ganz runterscrollen: ich habe 300 Einträge, die habe ich auf einen Schlag geholt. Aber es werden immer nur die entsprechenden in dem Viewport angezeigt.

Und das macht eben diese Virtualize-Komponente komplett automatisch für mich. Und wir sehen auch hier - ich mache es wieder eins kleiner - im Network-Tab; wir sehen auch hier: es passiert wirklich nur ein einziger Call, wie ihr es hier seht. Das heißt also, das ist wirklich alles In-Memory.

Okay? So jetzt gehen wir mal auf "Conferences via Data Provider". Hier ist jetzt anders. Hier - seht ihr - werden tatsächlich - und ihr könnt vielleicht sogar über das Streaming erkennen, dass manche Items da unten so einen Defaulttext, so einen Platzhalter erst mal bekommen, während ich hier einfach runterscrolle. Und jedes Mal werden entsprechende Datenblöcke immer nur geholt. Das heißt, jedes Mal werden unterschiedliche Konferenzen geholt, basierend auf der Parametrisierung, wie ich es eben in meiner Komponente bzw. in meiner Page verdrahte.

Wie schaut das aus? Das schaut folgendermassen aus: Das ist nämlich das hier. Ich habe jetzt keine Items mehr, sondern einen ItemsProvider und habe in dem ItemsProvider, das ist am Ende des Tages ein Delegate mit einer speziellen Signatur (und jetzt muss ich ein bisschen Platz machen hier Leute).

Das heißt, was ich reinbekomme, ist ein sogenannter ItemsProviderRequest auf dem Request gibt es einen StartIndex und es gibt ein CancellationToken und dann kann ich mir eben berechnen, was ich brauche und gebe diese Information dann an den Aufruf meines APIs. Also wirklich in diesem Fall mein gRPC-Service mit, weil das Interface von meinem gRPC-Service schaut folgendermaßen aus. Da gibt es eine Methode ListConferencesAsync. Und da gebe ich Query-Parameters rein. Und diese Query Parameters sind im Endeffekt nichts anderes als der Startindex und eine Pagesize. Das heißt, es ist so die klassische Vorgehensweise für Paging.

Genau, und das ist eigentlich alles. Und wenn es dann zurückkommt, dann gebe ich ein ItemsProviderResult zurück. Und voila - habe ich genau den Effekt, den ich euch gerade eben schon im Browser gezeigt habe.

Das finde ich ein richtig cooles Feature, was eigentlich fast Standard werden sollte, wenn man mit Tabellen oder mit Datagrid-ähnlichen Systemen arbeitet.

Gut, next step: Verbesserungen im Komponentenmodell. In .NET 3.1 also Blazor 3.2 war es ja immer so: Ich hatte eine große App.css oder das war ja irgendwie totaler Quark.

Ich musste den ganzen Kram, die ganzen Styles; erstens musste ich es im CSS machen, ja? Es gab zwar schon auch die Möglichkeit, es in SASS beispielsweise abzubilden, aber es wurde nie so wirklich propagiert, auch nicht von Microsoft. Und ich hatte nie wirklich die Möglichkeit, out of the box so Component-Styles zu machen, um dann wirklich gekapselt Komponenten zu bauen. Das ist jetzt in .NET 5 anders. In .NET 5 habe ich die Möglichkeit, sozusagen Styles nur für meine Komponente zu machen, so wie ich es eigentlich aus den anderen SPA-Framework auch kenne.

Weil ich meine, wenn ich in Angular über die CLI eine neue Komponente anlege, dann bekomme ich das automatisch erzeugt. Und so ist es jetzt im .NET 5 eben auch. Ich habe zu meiner. z.B. index.razor habe ich dann eine index.razor.css. Das wird dann intern sozusagen ge-namespaced auf die Komponente; wird dann zusammengebundelt. Das ist der Punkt hier. Das heißt, ich muss noch einen Verweis haben in meiner index.html auf dieses gebundelte File, wo dann der Compiler - das ist nämlich ein Compile-Step -; wo der Compiler aus allen einzelnen CSS-Files ein einziges CSS baut, welches ich dann eben referenzieren muss in meine index.html.

Und out-of-the-box ist CSS unterstützt. Wir verwenden aber auch SASS bzw. unsere Leute verwenden eigentlich ausschließlich SASS und kein natives CSS mehr. Und das kann man auch in Blazor WebAssembly ganz gut unterstützen, z.B. über so eine Open Source Komponente, die auch über Nuget verfügbar ist.

Die nennt sich LibSassBuilder. Die funktioniert vor allem Cross Platform. Die funktioniert auf Windows, die funktioniert auf Linux und die funktioniert auf macOS.

In der offiziellen Blazor-Dokumentation ist ein anderes Tool verlinkt. Das möchte ich euch nicht unbedingt empfehlen, weil es a) veraltet ist und b) glaube ich nur unter Windows läuft.

Wie schaut das aus? Dieses Feature? Das ist hier "IsolatedCssSass". Ähm, keine Ahnung? "Don't save". So. Das schaut folgendermaßen aus. Das Visual Studio auf dem Mac ist mittlerweile genauso langsam wie unter Windows.

Okay. Darf ich jetzt hier? Jetzt darf ich aufziehen. Wunderbar. Also wir haben zum Beispiel einmal hier. Hier haben wir jetzt so was. Hier haben wir einmal das "NavMenu.razor" und dann haben wir hier unten drunter NavMenu.razor.css.

Das ist ein wirklich komplett spezial und speziell für das NavMenu und genauso wie oben beim "MainLayout.razor". Hier habe ich jetzt aber ein SCSS drinnen, weil ich nämlich eine Dependency drinnen hab. Das ist dieser LibSassBuilder und dieser LibSassBuilder ist auch einfach nur ein Build Task, der sich reinhängt. Das heißt, wann immer gebaut wird, kompilierte er das SCSS nach CSS und danach hängt sich dann der Blazor Build Task dran - das heißt also, dass ist automatisch dann auch gebundelt für meine Blazor Client-Anwendung und das einzige, was dafür notwendig ist, ist wie erwähnt dieses eine Stylesheet.

Das ist nämlich Projektname - also "BlazorWasmSass.Client" und dann ".styles.css". Das ist der Anker, den wir verwenden müssen, um es dann generiert zu bekommen. Schauen wir es uns mal an!

Ah, ich gucke gerade im Chat also die Performance Features scheinen teilweise sehr gut anzukommen: "impressive", "Nicht schlecht die Performance" oder "Das ist ja mal ein richtig geiles Feature". Ich glaube, das war zu der Virtualize-Komponente.

So, jetzt versuchen wir es mal hier nochmal zum Start zu bekommen. Das schaut natürlich ein bisschen gaga aus und machen hier mal einen Reload.

Diese Performance ist nicht beeindruckend, aber da müssen wir vielleicht nochmal wegen der Streamingplattform gucken. Okay, also was ist hier jetzt passiert? Im Endeffekt gibt es hier ein.... Das ist jetzt dieses Stylesheet und ihr seht hier, ich mache mal ein Pretty und ich mache es mal ein bisschen größer und auch hier ein bisschen größer.

Es heißt, ihr sehr jetzt hier: Das ist auch MainLayout gekommen. Das ist also der Teil hier, nämlich SCSS kompiliert nach CSS und das hier ist das CSS. Und das hier unten ist dann das entsprechende NavMenu, was dann ebend der Teil hier ist. Und das ist eigentlich schon alles, was passiert und wenn wir uns jetzt einmal so einen Selektor angucken "NavbarToggler". Und dann seht ihr hier: Das ist jetzt das, was ich vorhin bezeichnet habe, als Namespace sozusagen. Das heißt also, das gilt wirklich. Nur dieser Styles gilt wirklich nur für dieses Element von dieser Komponente. Also wirklich scoped.

Und das ist natürlich unabdingbar, um wirklich auch den Weg zu einer echten Komponentenorientierung sinnvoll machen zu können, um das eben nicht mehr global halten zu müssen. Der nächste Schritt dahin ist, dass ich nicht nur CSS und SASS, sondern auch JavaScript isolieren kann. Ich musste ja bisher immer alles auf Window pumpen.

Ja. Ob ich jetzt mit Browser APIs wie z.B. bei Progressive Web Apps kommunizieren möchte oder ob ich eine Third-Party Komponente einbinden muss, weil es noch keine native Blazor dafür gibt. Ich muss mich ja irgendwie mit JavaScript Interop auseinandersetzen und da musste ich es bisher immer auf Window machen und muss dann irgendein Namespacekonzept ausdenken, weil eben JavaScript Modules-Entwicklung nicht unterstützt war. Das ist jetzt aber Geschichte. Mit .NET 5 werden JavaScript Modules unterstützt und über die IJsRuntime in meinem Blazorcode kann ich das wunderbar kapseln.

Ich zeig es am besten einfach mal - das ist das simpelste. IsolatedJS. So, also ich habe hier einen Ordner mit dem Komponentenfeature Webcam. Da habe ich einen IWebcamService drinnen, dann wird es einen WebcamService geben, der dieses Interface implementiert.

Ich habe eine Razor-Datei dazu. Ich habe die entsprechende CSS-Datei dazu gepackt, weil es ja auch genau nur für diese Komponente machen möchte. Muss jetzt aber hier immer noch dieses JavaScript Interop-File; das muss ich immer noch bei wwwroot unterbringen, weil das ja ausgeliefert werden muss an den Browser. Und das ist aktuell noch nicht - ich sag mal - in dem Komponentenbundle dann mit drin, sondern das muss eben noch an dieser wwwroot-Stelle liegen und ausgeliefert werden.

Aber ich habe hier halt jetzt ganz normale Export-Functions einmal "export function startVideo()", einmal "export function clearPicture()" und so weiter und so fort. Das heißt also JavaScript Module Code und das kann ich jetzt wiederum implementieren in meiner WebcamService und kann das vor allem auch mit der neuen Schnittstelle IAsync disposable umsetzen.

Was ich da machen muss, ist: Ich muss mir einfach eine sogenannte IJSObject Reference holen und kann dann tatsächlich Import-Code ausführen, also wie ich es in JavaScript selber auch machen würde. Also ich importiere jetzt dieses JavaScript Modul in meinen Code hinein. Und das war es dann. Das heißt also, ich muss das auch nicht mehr in der index.html irgendwo verdrahten. Für diejenigen, die Blazor machen, die wissen, ich müsste jetzt eigentlich hier noch ein Script Tag machen mit einem Link auf dieses Webcam.js. Das kann ich mir sparen, weil eben alles abgefrühstückt wird innerhalb von dieser Webcam Service Implementierung über dieses neue Feature des Importierens.

Und alles andere ist dann ganz normales invoke und später dann eben hier das saubere Aufräumen und Auflösen der Referenzen und des Speichers über IAsyncDisposable.

Das brauche ich eigentlich nicht zu zeigen, weil ja, das ist hauptsächlich struktureller Benefit, denn wir hier haben. So.

Last but not least ein Feature, wo ich mich extrem darauf gefreut habe, nämlich "Lazy Loading". Also bin ich doch jetzt schon Komponenten bauen kann, wo ich CSS dazupacken kann, wo ich JavaScript isoliert dazupacken kann, dann will ich doch die Möglichkeit haben, dass ich mir eine Komponentenbibliothek baue als RCL, also Razor Class Library, wo ich das dann komplett wegkapseln kann.

Ich möchte diese Webcam als eigene DLL vielleicht auch auf Nuget stellen können und brauche aber da vielleicht Dependency Injection drin. Oder weil ich irgendwelche Abhängigkeiten über Services abgebildet habe und habe vielleicht sogar noch eine Kette von Abhängigkeiten, also Dependencies-on- Dependencies.

Da hätte ich mir gewünscht, dass das irgendwie jetzt .NET 5 kommt, aber in .NET 5 kommt leider nur die Schmalspurvariante davon. In .NET 5 kommt sozusagen die Möglichkeit, dass ich DLLs nachladen kann.

Und genau das ist es dann aber auch. Es ist wirklich nur das Nachladen von einer DLL. Ich habe nicht die Möglichkeiten einen Initialisation-Code irgendwie dann ablaufen zu lassen oder ich habe keine Hooks dafür meinen Init-Code irgendwie ausführen zu können. Beispiel: wenn ich diesen Webcam Service habe, dann habe ich ja eine Dependency Injection da drinnen. Entweder über das Interface IWebcamService oder eben WebcamService selber. Aber ich möchte das hier initiieren in meine Komponente hinein.

Das geht aber nicht, weil ich keine Möglichkeit habe, nachdem die Komponente oder nachdem die DLL dynamisch z.B. über die Route geladen wurde, dass ich mich da reinhängen. Ich zeig euch das mal! Ich habe auch ein Beispiel dafür gebaut, nämlich "LazyLoading".

Und dieses "LazyLoading" schaut nun folgendermaßen aus: also ich habe hier eine RCL - eine Razor Class Library - und in dieser RCL ist alles gekapselt, alles das, was ihr vorhin gesehen habt in dem Client-Projekt, in dem wwwroot;

Entschuldigung. Quatsch. In dem Webcam-Folder ist jetzt hier komplett gekapselt in einer eigenen DLL; genau das gleiche. Keine Magie dahinter. Was ich dafür ändern musste, ist folgendes: du musst für Lazy Loading du einmal dem Compiler sagen, dem Build System sagen, welche DLLs lazy load-ed werden sollen oder können können. Und dann musst du dem Router auch noch sagen, welche zusätzlichen Assemblies denn lazy load-ed werden können oder sollen und diese musst du dann entsprechend auflösen, basierend auf der Route.

Also ich habe ein Slash Webcam und hinter Slash Webcam befindet sich dann hier meine Webcam. Okay, das ist aber nicht wirklich Komponenten- basiert, liebes Blazor-Team, sondern das ist Page-basiert ja. Also ich muss mir schon irgendwie eine Page bauen, die ich dann über eine Route erreichen kann. Das ist mir momentan ehrlich gesagt ein bisschen zu wenig. Ich lasse es dennnoch einmal laufen, weil die Grundidee und die Grundausstattung sozusagen die Basisausstattung ist eigentlich schon ganz gut.

Um. Aber es ist auch noch nicht ausreichend. Er baut noch.

Du schiesst dir dann aber nicht den Videostream vom Webinar weg, ja?

Wieso?

Wenn du jetzt die Webcam darauf zugreifen lässt; nicht, dass wir dich dann nicht mehr sehen, haha.

Marco Du bist echt. Du bist ein Fuchs. Da bin ich ja jetzt mal gespannt, was jetzt passiert? No risk, no fun, Marco, oder?

Ja.

Erst einmal müssen wir hier wieder aufräumen. Das ist ja dieses Single Package App Thema mit gecachtem Anwendungsersatz. So.

Dann geh wir mal hier mal in... Ich muss mal hier kleiner machen, kleiner und gehen hier auf Network.

So, also in einer Blazor WebAssembly-Anwendung haben wir ja dieses Metadatenfile "blazor.boot.json". Das wird ja jeder schon einmal sich angeguckt haben.

Und in diesem "blazor.boot.json" stehen ja alle möglichen Metadaten für die clientseitige Runtime. Und eine davon ist jetzt neu Lazy Assembly und in dem Lazy Assembly; hier; steht jetzt unsere Webcam drinnen mit dem entsprechenden Hash. Wenn ich das jetzt hier lade. Dann seht ihr gleich Webcam wird jetzt hier diese DLL dynamisch nachgeladen. Ihr habt auch so ein kurzes Flackern gesehen - das kurze Flackern stammt hier aus dem Router, wo ich nämlich sage Okay, wenn was geladen wird, bitte zeig mal so ein schönes blaues Banner mit weißem Text an.

Aber das ging jetzt natürlich hier auf localhost so schnell, dass man es garnicht wirklich lesen konnte. Und wenn ich jetzt "Start video" mache, Marco, soll ich?

Ich moderiere es dann zu Ende.

Haha! Komm, wir probieren es. Ha! Es ist nämlich die Laptopkamera. *****. Dann funktioniert das Ganze nämlich. Das heißt also ja, ich habe so eine Art Kapselung. Ich habe so eine Art Modularisierung. Aber noch nicht, da, wo ich sie haben möchte, damit ich dahinkommen kann, bin ich im Kontakt mit einem Open Source Entwickler von dem Projekt Blazor-Lazy-Loading. Das gibt's schon seit längerem auch für Pre-.NET 5 und er ist gerade dabei, das zu portieren nach .NET 5.

Kleine Geschichte am Rande. Der Typ ist so cool und sein Framework ist so clever implementiert, dass das Blazor-Team seinen abgeänderten Router verwendet hat, um den in .NET 5 zu adaptieren, um ebendiese Lazy Loading-Features über den Router überhaupt zur Verfügung stellen zu können, sind aber den Schritt Richtung echter Modularisierung leider nicht weiter gegangen, sondern das bleibt jetzt aktuell noch an diesem OpenSource Projekt hängen. Also nicht alles ist Gold, was glänzt. Aber wie wird es denn weitergehen?

Wie gesagt, es dauert ja keine, keine elf Monate mehr, dann haben wir schon die finale Version von .NET 6 und das erste Preview von .NET 6, damit rechne ich im Februar oder spätestens im März. Das heißt, wir werden ja die ganze Zeit wieder teilhaben dürfen an der Weiterentwicklung von .NET und natürlich auch von Blazor.

Und dieser Screenshot hier, Marco, ich weiß nicht, ob du gestern beim Tec-Check aufgepasst hast, aber der Screenshot gestern war anders, nämlich dieser eine Punkt hier war nicht durchgestrichen.

Der wurde heute Nacht abgedated. Das ist halt Open Source - agile Entwicklung, basierend auf Timelines und Ressourcen. Also ganz wichtig natürlich AOT- Kompilierung, das wird ein großes Feature werden. Das heißt Ahead of Time-Compilation, damit wir nicht mehr die ganze Anwendung. Ja, ich sage mal zur Laufzeit interpretiert ausführen lassen müssen, sondern dass wir eben schon vor kompilierte Punkt-WASM Module haben, die dann auch tatsächlich über WebAssembly ausgeführt werden können. Ein echtes Hot-Reload für Blazor, eingebaut ins Framework und eingebaut in die IDEs und so weiter und so fort.

Und eine Idee war eben auch Multi Threading-Unterstützung. Das haben sie jetzt heute Abend oder heute Nacht rausgenommen. Vermutlich deswegen, weil es halt nur sehr, sehr wenige Browser wirklich unterstützen und teilweise auch nur hinter einem Flag. Es ist nämlich noch nicht wirklich komplett flächendeckend in allen Browsern umgesetzt. Das heißt also, echtes Multi Threading wird es dann voraussichtlich auch für .NET nicht geben in Blazor WebAssembly. Ihr könnt euch ja auf dieses GitHub-Issue, was ich hier verlinkt habe, subscriben.

Ich bin da regelmäßig drauf um zu gucken, was vor sich geht. Da bekommt man teilweise auch wirklich sehr interessante Insides über die Funktionsweise des Ganzen.

Gut, dann bin ich tatsächlich am Ende, wenn ich das mal netto betrachte, waren 66 Minuten, also quasi 6 6 6 - The Number of the Beast. Vielen Dank fürs Beiwohnen. Vielen Dank fürs Ausharren. Vielen Dank wahrscheinlich jetzt auch gleich für die rege Unterhaltung. Die Demos, die ich gezeigt habe, die hab ich wieder bei uns aufs GitHub gepackt.

Ansonsten, wie schon zu Eingang erwähnt: wenn ihr Fragen habt, bitte ganz einfach per Email melden. Wenn wir das jetzt nicht gleich hier App frühstücken. Wenn euch das ganze gefallen hat, dann betreibt auch gerne ein bisschen Werbung für uns. Vielleicht über Twitter oder einfach nur von Mund zu Mund und ansonsten würde ich sagen, Marco, mögen die Spiele beginnen.

Sie wünschen sich Unterstützung durch unsere Experten in Ihrem Projekt?

Slidedeck zu "Blazor WebAssembly: Neues in .NET 5"

Kommende Webinare: jetzt kostenlos anmelden

@ngrx/signals: Reaktives State-Management auf Komponentenebene

Yannick Baron | 03.04.2024 | 10:30 Uhr

Transparente AI: Tracing- und Debugging-Techniken für LLM-Anwendungen

Marco Frodl | 15.05.2024 | 10:30 Uhr

Weitere Artikel zu ASP.NET Core, Blazor, SPA, WebAssembly

Database Access with Sessions
.NET
KP-round

Data Access in .NET Native AOT with Sessions

.NET 8 brings Native AOT to ASP.NET Core, but many frameworks and libraries rely on unbound reflection internally and thus cannot support this scenario yet. This is true for ORMs, too: EF Core and Dapper will only bring full support for Native AOT in later releases. In this post, we will implement a database access layer with Sessions using the Humble Object pattern to get a similar developer experience. We will use Npgsql as a plain ADO.NET provider targeting PostgreSQL.
15.11.2023
Old computer with native code
.NET
KP-round

Native AOT with ASP.NET Core – Overview

Originally introduced in .NET 7, Native AOT can be used with ASP.NET Core in the upcoming .NET 8 release. In this post, we look at the benefits and drawbacks from a general perspective and perform measurements to quantify the improvements on different platforms.
02.11.2023
ASP.NET Core
favicon

Architektur-Modernisierung: Migration von WCF zu gRPC mit ASP.NET Core – ein pragmatischer Ansatz

Viele Projekte mit verteilten Anwendungen in der .NET-Welt basieren noch auf der Windows Communication Foundation (WCF). Doch wie kommt man weg von der "Altlast" und wie stellt man seinen Code auf sowohl moderne als auch zukunftssichere Beine? Eine mögliche Lösung ist gRPC.

13.04.2023
Blazor
favicon

gRPC Code-First mit ASP.NET Core 7 und Blazor WebAssembly

Wie in allen anderen browserbasierten Single-Page-Application (SPA) Frameworks, ist Blazor WebAssembly JSON-over-HTTP (über Web- oder REST-APIs) die bei weitem häufigste Methode, um Daten auszutauschen und serverseitige Vorgänge auszulösen. Der Client sendet eine HTTP-Anfrage mit JSON-Daten an eine URL, mitunter über unterschiedliche HTTP-Verben. Anschließend führt der Server eine Operation aus und antwortet mit einem HTTP-Statuscode und den resultierenden JSON-Daten. Warum sollte man das ändern? Nun, es gibt Gründe - vor allem wenn man in einem geschlossenen System ist und .NET sowohl im Frontend als auch im Backend einsetzt.
30.03.2023
Blazor
favicon

Blazor WebAssembly in .NET 7: UI-Performance-Optimierung auf Komponentenebene

Stockende UI, keine Reaktion nach dem Klick auf einen Button oder einer Eingabe in einem Feld - dies sind nur wenige Beispiele alltäglicher Probleme, die der Nutzung von Client-Anwendungen im Allgemeinen, und bei Webanwendungen im Speziellen, immer wieder auftreten können. In diesem Artikel schauen wir uns an, wie wir komponentenbasierte UIs in Blazor WebAssembly optimieren können, um dadurch eine für die Benutzer zufriedenstellende Geschwindigkeit und ein flüssiges UI zu bekommen.
29.03.2023
Blazor
sg

Understanding and Controlling the Blazor WebAssembly Startup Process

There are a lot of things going on in the background, when a Blazor WebAssembly application is being started. In some cases you might want to take a bit more control over that process. One example might be the wish to display a loading screen for applications that take some time for initial preparation, or when users are on a slow internet connection. However, in order to control something, we need to understand what is happening first. This article takes you down the rabbit hole of how a Blazor WASM application starts up.
07.03.2023

Unsere Webinare

Unsere Artikel

Mehr über uns