© deomis/Shutterstock.com
Teil 2: Blazor-Syntax, Zustände, Interoperabilität und Libraries

Blazor unter der Haube


Im ersten Teil des Beitrags wurden die architektonischen Unterschiede zwischen Blazor Server und Blazor WebAssembly geklärt. Nun geht es um die Razor-Syntax, Komponentenzustände, Razor Class Libraries und die Interoperabilität mit JavaScript.

Webanwendungsentwickler nutzen in der .razor-Datei einer Razor Component – sowohl in Blazor Server als auch Blazor WebAssembly – im Wesentlichen die gleiche Razor-Syntax wie bei Views im Model-View-Controller-Modell (MVC) und Razor Pages. Im Detail gibt es aber dennoch einige Unterschiede zwischen den Razor-Anwendungsgebieten, siehe dazu die ausführliche Tabelle 1.

In Razor Components ist die Syntaxprüfung strenger; während in MVC und Razor Pages ein fehlendes schließendes Tag nur zu einer Warnung führt („Element 'xy' requires end tag“), kommt es in Razor Components zu einem Kompilierungsfehler RZ9980 „Unclosed tag 'xy' with no matching end tag“.

Zustandshaftigkeit

Klassische Webanwendungen mit Server-side Rendering sind zustandslos: Ein HTTP-Request geht ein, wird verarbeitet und eine Antwort wird erzeugt. Danach werden alle gesetzten Variablen vernichtet. Konkret in ASP.NET und ASP.NET Core wird bei jedem Aufruf immer wieder eine neue Instanz der Page-Klasse (bei Web Forms), der Controller-Klasse (bei MVC) bzw. des Page Models (bei Razor Pages) erzeugt. Man braucht Techniken wie Cookies, Hidden Fields oder URL-Parameter bzw. darauf aufsetzende Abstraktionen wie Session-Variablen oder Viewstate, um Werte von einem zum nächsten HTTP-Aufruf weiterzugeben.

Nichts davon ist in Blazor Server und Blazor WebAssembly notwendig, denn eine Razor Component lebt solange sie angezeigt wird (auch wenn sich nichts rendert oder ihr Inhalt per CSS unsichtbar gemacht wurde). Dass Cookies, Hidden Fields oder URL-Parameter nicht notwendig sind, zeigt schon das Zählerbeispiel (Counter.razor), das Microsoft in der Standardprojektvorlage mitliefert. Wegen der Zustandshaftigkeit wird der Counter bei jedem Klick erhöht. In klassischen Webanwendungen würde er immer nur von 0 bis 1 hochzählen. Wechselt der Benutzer jedoch im Menu zu einer anderen Komponente, wird sie inaktiv und der Zustand der Komponente wird auf dem Server gelöscht.

Zwischen Blazor Server und Blazor WebAssembly gibt es aber auch hier wieder einen Unterschied: Bei Blazor WebAssembly legt die Komponenteninstanz im Webbrowser, bei Blazor Server zusammen mit dem Virtual DOM auf dem Webserver.

Eine Komponente verliert ihren Zustand, wenn sie nicht mehr angezeigt wird. Wenn sie später erneut angezeigt wird, wird sie instanziiert. Um den Zustand über mehrere Instanzen hinweg zu verwalten, muss man den Zustand in einer per Dependency Injection erzeugten Instanz halten oder persistieren (auf dem Server oder im Client).

MVC View (.cshtml)

Razor Page (.cshtml)

Razor Component (.razor)

Code-behind-Datei

-

.cshtml.cs

.razor.cs

Seitendirektive mit Route

-

@pages "/a/b/{x}/{y}"

@page "/a/b/{x}/{y}"

Mehrfachrouten

-

-

@page "/a/b/{x}/{y}"

@page "/ab/{x}/{y}"

Verweis auf Code-Datei

@model name

@model name

@inherits name

Nutzung von Code aus Code-Datei

@Model.xy

@Model.xy

@this.xy oder @base.xy

Namensräume einbinden

@using System

@using System

@using System

Dependency Injection

@inject IAbc abc

Realisieren einer Schnittstelle

-

@implements IDisposable

Annotieren einer Komponente

-

@attribute [Authorize]

Verweis auf View Bag

@ViewBag.Name

-

Verweis auf View Data

@ViewData["Name"]

-

Codeblock

@{

int anz = 5;

DateTime start = DateTime.Now;

string ausgabe = "<i>kursiv</i>";

var orte = new List<string>

() { "Essen", "Dortmund", "Bochum" };

}

@code {

// Codeblock

int anz = 5;

DateTime start = DateTime.Now;

string ausgabe = "<i>kursiv</i>";

List<string> orte = new List<string>

() { "Essen", "Dortmund", "Bochum" };

}

Kommentarblock

@*

Dies ist ein

Kommentarblock *@

Ausgabe lokale Variable

@name

Ausgabe Modelvariable

@Model.name

@name

Rohe HTML-Ausgabe

@Html.Raw(name)

@((MarkupString)name)

Notwendige Klammerung bei Ausdrücken

Dies ist die @(anz).Seite!

Ergebnis: @(anz * 10 + 2)

Autor: @(new Autor("HS").ToString())

Bedingtes Markup

@if (anz < 100)

{<text>reiner Text</text> }

else

{ <div>Tag und Ausdruck @anz</div> }

Bedingte Formatierung mit style

<div style='Background-color:@(anz <5 && orte != null ? "#E0EEFA" : "red")'>

oder

<div style='@((anz <5 && orte != null ? "Background-color:#E0EEFA" : "Background-color:red"))'>

Bedingte Formatierung mit class

<div class='@((anz <5 && orte != null ? "bg-success" : "bg-danger"))'>

for-Schleife mit Taginhalt

int schrittweite = 2;

for (int i = 0; i < anz; i += schrittweite)

{

<div>@start.AddDays(i)</div>

}

for-Schleife mit reinem Textinhalt

for (int i = 0; i < anz; i += schrittweite)

{

<text> Seite @i

noch mehr reiner Text </text>

}

oder

f...

Neugierig geworden? Wir haben diese Angebote für dich:

Angebote für Teams

Für Firmen haben wir individuelle Teamlizenzen. Wir erstellen Ihnen gerne ein passendes Angebot.

Das Library-Modell:
IP-Zugang

Das Company-Modell:
Domain-Zugang