ASP.NET Core-Razor-Klassenbibliotheken (RCLs) mit statischem serverseitigem Rendering (statischer SSR)

Dieser Artikel enthält einen Leitfaden für Komponentenbibliotheksersteller*innen, die die Unterstützung für statisches serverseitiges Rendering (statisches SSR) in Erwägung ziehen.

Blazor fördert die Entwicklung eines Ökosystems von Open-Source- und kommerziellen Komponentenbibliotheken, die zuvor als Razor Klassenbibliotheken (RCLs) bezeichnet wurden. Entwickler*innen können auch wiederverwendbare Komponenten für das private Freigeben für mehrere Apps innerhalb ihrer eigenen Unternehmen erstellen. Im Idealfall werden Komponenten für die Kompatibilität mit möglichst vielen Hostingmodellen und Renderingmodi entwickelt. Statisches SSR führt zusätzliche Einschränkungen ein, die schwieriger zu unterstützen sind als interaktive Renderingmodi.

Grundlegendes zu den Funktionen und Einschränkungen von statischem SSR

Bei statischem SSR handelt es sich um einen Modus, in dem Komponenten ausgeführt werden, wenn der Server eine eingehende HTTP-Anforderung verarbeitet. Blazor rendert die Komponente als HTML, das dann in der Antwort enthalten ist. Sobald die Antwort gesendet wurde, werden die serverseitige Komponente und der Rendererstatus verworfen, sodass nur noch HTML im Browser vorhanden sind.

Der Vorteil dieses Modus ist günstigeres, skalierbareres Hosting, da keine laufenden Serverressourcen zum Speichern des Komponentenzustands erforderlich sind. Außerdem muss es keine fortlaufende Verbindung zwischen Browser und Server geben, und im Browser ist keine WebAssembly-Workload nötig.

Standardmäßig können alle vorhandenen Komponenten weiterhin mit statischem SSR verwendet werden. Der Nachteil dieses Modus ist jedoch, dass Ereignishandler, wie z. B. @onclick†, aus folgenden Gründen nicht ausgeführt werden können:

  • Es gibt keinen .NET-Code im Browser, um sie auszuführen.
  • Der Server hat sofort alle Komponenten- und Rendererzustände verworfen, die zum Ausführen von Ereignishandlern oder zum erneuten Rendern derselben Komponenteninstanzen erforderlich wären.

†Es gibt eine Ausnahme für den @onsubmit-Ereignishandler für Formulare, die unabhängig vom Rendermodus immer funktionsfähig ist.

Dies entspricht dem Verhalten von Komponenten während des Prerendering, bevor eine Blazor-Leitung oder eine Blazor WebAssembly-Runtime gestartet wird.

Für Komponenten, deren einzige Rolle das Erstellen von schreibgeschütztem DOM-Inhalten ist, sind diese Verhaltensweisen für statisches SSR ausreichend. Bibliotheksersteller*innen müssen jedoch überlegen, welchen Ansatz Sie beim Aufnehmen interaktiver Komponenten in ihre Bibliotheken verfolgen möchten.

Optionen für Komponentenersteller*innen

Es gibt drei Hauptansätze:

  • Kein Verwenden interaktiven Verhaltens (Einfach)

    Für Komponenten, deren einzige Rolle das Erstellen von schreibgeschützten DOM-Inhalten ist, müssen Entwickler*innen keine speziellen Maßnahmen ergreifen. Diese Komponenten funktionieren immer mit jedem Rendermodus.

    Beispiele:

    • Eine "Benutzerkarte"-Komponente, die Daten einer Person lädt und sie in einer stilisierten Benutzeroberfläche mit einem Foto, einer Position und weiteren Informationen rendert
    • Eine "Video"-Komponente, die als Wrapper um das <video>-HTML-Element fungiert, und so das Verwenden in einer Razor-Komponente erleichtert
  • Erfordern von interaktivem Rendering (Einfach)

    Sie können festlegen, dass Ihre Komponente nur mit interaktivem Rendering verwendet wird. Dies schränkt die Anwendbarkeit Ihrer Komponente ein, bedeutet jedoch, dass Sie sich auf beliebige Ereignishandler verlassen können. Selbst dann sollten Sie jedoch vermeiden, einen bestimmten @rendermode zu deklarieren und den App-Ersteller*innen, die Ihre Bibliothek nutzen, zu erlauben, einen auszuwählen.

    Beispiele:

    • Eine Videobearbeitungskomponente, in der Benutzer*innen Segmente von Videos verbinden und neu anordnen können. Selbst wenn es eine Möglichkeit zum Darstellen dieser Bearbeitungsvorgänge mit einfachen HTML-Schaltflächen und -Formularbeiträgen gäbe, wäre die Benutzeroberfläche ohne echte Interaktivität inakzeptabel.
    • Ein gemeinsam genutzter Dokument-Editor, der die Aktivitäten anderer Benutzer*innen in Echtzeit anzeigen muss
  • Verwenden interaktiver Verhaltensweisen mit Entwerfen für statisches SSR und progressive Verbesserungen (Erweitert)

    Viele interaktive Verhaltensweisen können nur mithilfe von HTML-Funktionen implementiert werden. Mit einem guten Verständnis von HTML und CSS können Sie häufig eine nützliche Baseline der Funktionalität erzeugen, die mit statischem SSR funktioniert. Sie können weiterhin Ereignishandler deklarieren, die erweitertere, optionale Verhaltensweisen implementieren, die nur in interaktiven Rendermodi funktionieren.

    Beispiele:

    • Eine Rasterkomponente. Bei statischem SSR unterstützt die Komponente nur das Anzeigen von Daten und das Navigieren zwischen Seiten. Dies wird mit <a>-Links implementiert. Beim Verwenden mit interaktivem Rendering kann die Komponente Livesortierung und -filterung hinzufügen.
    • Eine TabSet-Komponente. Solange das Navigieren zwischen Registerkarten mithilfe von <a>-Links ermöglicht wird, und Zustand nur in URL-Abfrageparametern aufrechterhalten wird, kann die Komponente ohne @onclick funktionieren.
    • Eine erweiterte Komponente zum Hochladen von Dateien. Bei statischem SSR verhält sich die Komponente möglicherweise als native <input type=file>-Komponente. Beim Verwenden mit interaktivem Rendering kann die Komponente auch den Uploadfortschritt anzeigen.
    • Ein Aktienticker. Bei statischem SSR kann die Komponente den Aktienkurs zum Zeitpunkt des Renderns des HTML-Codes anzeigen. Beim Verwenden mit interaktivem Rendering kann die Komponente den Aktienpreis schließlich in Echtzeit aktualisieren.

Für jede dieser Strategien gibt es auch die Möglichkeit, interaktive Features mit JavaScript zu implementieren.

Um zwischen diesen Ansätzen zu wählen, müssen Ersteller*innen von wiederverwendbaren Razor-Komponenten einen Kosten-/Nutzen-Kompromiss erzielen. Ihre Komponente ist nützlicher und verfügt über eine breitere potenzielle Benutzerbasis, wenn sie alle Rendermodi unterstützt, einschließlich dem statischen SSR. Das Entwerfen und Implementieren einer Komponente, die jeden Rendermodus unterstützt und möglichst gut nutzt, bedeutet jedoch mehr Arbeit.

Verwenden der @rendermode-Anweisung

In den meisten Fällen sollten Ersteller*innen wiederverwendbarer Komponenten keinen Rendermodus angeben, auch wenn Interaktivität erforderlich ist. Der Grund hierfür ist, dass Komponentenersteller*innen nicht wissen, ob die App Unterstützung für InteractiveServer, InteractiveWebAssembly oder beide mit InteractiveAuto bietet. Komponentenersteller*innen überlassen diese Wahl den App-Entwickler*innen, wenn sie keinen @rendermode angeben.

Selbst wenn die Komponentenersteller*innen der Meinung sind, dass Interaktivität erforderlich ist, kann es dennoch Fälle geben, in denen ein App-Entwickler*innen es als ausreichend erachten, nur statisches SSR zu verwenden. Eine Kartenkomponente mit Zieh- und Zoominteraktivität kann beispielsweise Interaktivität erfordern. Einige Szenarios benötigen jedoch möglicherweise nur das Rendern eines statischen Zuordnungsimages auf und erfordern keine Features zum Bewegen oder Zoomen.

Der einzige Grund, warum Ersteller*innen wiederverwendbarer Komponenten die @rendermode-Anweisung für ihre Komponente verwenden sollte, ist eine grundsätzlich mit einem bestimmten Rendermodus verbundene Implementierung, die mit einem anderen Modus zu einem Fehler führen würde. Ziehen Sie eine Komponente mit dem zentralen Zweck in Betracht, direkt mit dem Hostbetriebssystem über Windows- oder Linux-spezifische APIs zu interagieren. Eventuell kann eine solche Komponente nicht in WebAssembly verwendet werden. In diesem Fall ist es sinnvoll, @rendermode InteractiveServer für die Komponente zu deklarieren.

Streamingrendering

Wiederverwendbare Razor-Komponenten können für das Streamingrendering@attribute [StreamRendering] deklarieren ([StreamRendering]-Attribut-API). Dies führt zu inkrementellen Benutzeroberflächenupdates während des statischen SSR. Da dieselben Datenlademuster während des interaktiven Renderings unabhängig vom [StreamRendering]-Attribut inkrementelle Updates der Benutzeroberfläche durchführen, verhält sich die Komponente in allen Fällen ordnungsgemäß. Selbst wenn das Streaming des statische SSR auf dem Server unterdrückt wird, rendert die Komponente weiterhin den richtigen Endzustand.

Wiederverwendbare Razor-Komponenten können Links und erweiterte Navigation verwenden. <a>-HTML-Tags sollten entsprechende Verhaltensweisen mit oder ohne interaktive Router-Komponente erzeugen und unabhängig davon, ob die erweiterte Navigation auf einer Vorgängerebene im DOM aktiviert/deaktiviert ist.

Verwenden von Formularen für mehrere Rendermodi

Wiederverwendbare Razor-Komponenten können Formulare enthalten – entweder <form> oder <EditForm> –, da diese so implementiert werden können, dass sie sowohl in statischen als auch interaktiven Rendermodi funktionieren.

Betrachten Sie das folgende Beispiel:

<EditForm Enhance FormName="NewProduct" Model="Model" OnValidSubmit="SaveProduct">
    <DataAnnotationsValidator />
    <ValidationSummary />

    <p>Name: <InputText @bind-Value="Item.Name" /></p>

    <button type="submit">Submit</button>
</EditForm>

@code {
    [SupplyParameterFromForm]
    public Product? Model { get; set; }

    protected override void OnInitialized() => Model ??= new();

    private async Task Save()
    {
        ...
    }
}

Die Enhance-, FormName-und SupplyParameterFromFormAttribute-APIs werden nur beim statischen SSR verwendet und beim interaktiven Rendering ignoriert. Das Formular funktioniert sowohl beim interaktiven als auch beim statischen SSR ordnungsgemäß.

Vermeiden von APIs, die spezifisch für statisches SSR sind

Um eine wiederverwendbare Komponente zu erstellen, die in allen Rendermodi funktioniert, verlassen Sie sich nicht auf HttpContext, da dies nur beim statischen SSR verfügbar ist. Das Verwenden der HttpContext-API ist beim interaktiven Rendering nicht sinnvoll, da zu diesen Zeiten keine aktive HTTP-Anforderung vorhanden ist. Des Weiteren muss kein Statuscode festgelegt oder in die Antwort geschrieben werden.

Wiederverwendbare Komponenten können wie folgt je nach Verfügbarkeit einen HttpContext erhalten:

[CascadingParameter]
public HttpContext? Context { get; set; }

Der Wert ist beim interaktiven Rendering null und wird nur beim statischen SSR festgelegt.

In vielen Fällen gibt es bessere Alternativen zum Verwenden von HttpContext. Wenn Sie die aktuelle URL kennen oder eine Umleitung durchführen müssen, arbeiten die APIs von NavigationManager mit allen Rendermodi. Wenn Sie den Authentifizierungsstatus der Benutzer*innen kennen müssen, verwenden Sie den AuthenticationStateProvider-Dienst von Blazor anstatt HttpContext.User.