Fehlerbehandlung in ASP.NET Core Blazor-Apps

Hinweis

Dies ist nicht die neueste Version dieses Artikels. Informationen zum aktuellen Release finden Sie in der .NET 8-Version dieses Artikels.

Wichtig

Diese Informationen beziehen sich auf ein Vorabversionsprodukt, das vor der kommerziellen Freigabe möglicherweise noch wesentlichen Änderungen unterliegt. Microsoft gibt keine Garantie, weder ausdrücklich noch impliziert, hinsichtlich der hier bereitgestellten Informationen.

Informationen zum aktuellen Release finden Sie in der .NET 8-Version dieses Artikels.

In diesem Artikel wird beschrieben, wie Blazor Ausnahmefehler behandelt und wie Sie Apps entwickeln können, die Fehler erkennen und behandeln.

Ausführliche Fehler bei der Entwicklung

Wenn eine Blazor-App während der Entwicklung nicht ordnungsgemäß funktioniert, erhalten Sie nun ausführliche Fehlerinformationen von der App, die Sie beim Beheben des Problems unterstützen. Wenn ein Fehler auftritt, zeigen Blazor-Apps eine hellgelbe Leiste am unteren Bildschirmrand an:

  • Während der Entwicklung leitet die Leiste Sie an die Browserkonsole weiter, in der die Ausnahme angezeigt wird.
  • In der Produktion benachrichtigt die Leiste den Benutzer darüber, dass ein Fehler aufgetreten ist, und empfiehlt, die Seite im Browser neu zu laden.

Die Benutzeroberfläche für diese Fehlerbehandlung ist Teil der Blazor-Projektvorlagen. Nicht alle Versionen der Blazor-Projektvorlagen verwenden das data-nosnippet-Attribut, um Browsern zu signalisieren, die Inhalte der Fehlerbenutzeroberfläche nicht zwischenzuspeichern, aber alle Versionen der Blazor-Dokumentation wenden das Attribut an.

Passen Sie in einer Blazor-Web-App die Funktionalität in der MainLayout-Komponente an. Da das Taghilfsprogramm für Umgebungen (z. B. <environment include="Production">...</environment>) in Razor-Komponenten nicht unterstützt wird, injiziert das folgende Beispiel IHostEnvironment, um Fehlermeldungen für verschiedene Umgebungen zu konfigurieren.

Am Anfang von MainLayout.razor:

@inject IHostEnvironment HostEnvironment

Erstellen oder ändern Sie das UI-Markup für Blazor-Fehler:

<div id="blazor-error-ui" data-nosnippet>
    @if (HostEnvironment.IsProduction())
    {
        <span>An error has occurred.</span>
    }
    else
    {
        <span>An unhandled exception occurred.</span>
    }
    <a href="" class="reload">Reload</a>
    <a class="dismiss">🗙</a>
</div>

Passen Sie in einer Blazor Server-App die Funktionalität in der Pages/_Host.cshtml-Datei an. Das folgende Beispiel verwendet das Taghilfsprogramm für Umgebungen, um Fehlermeldungen für verschiedene Umgebungen zu konfigurieren.

Passen Sie in einer Blazor Server-App die Funktionalität in der Pages/_Layout.cshtml-Datei an. Das folgende Beispiel verwendet das Taghilfsprogramm für Umgebungen, um Fehlermeldungen für verschiedene Umgebungen zu konfigurieren.

Passen Sie in einer Blazor Server-App die Funktionalität in der Pages/_Host.cshtml-Datei an. Das folgende Beispiel verwendet das Taghilfsprogramm für Umgebungen, um Fehlermeldungen für verschiedene Umgebungen zu konfigurieren.

Erstellen oder ändern Sie das UI-Markup für Blazor-Fehler:

<div id="blazor-error-ui" data-nosnippet>
    <environment include="Staging,Production">
        An error has occurred.
    </environment>
    <environment include="Development">
        An unhandled exception occurred.
    </environment>
    <a href="" class="reload">Reload</a>
    <a class="dismiss">🗙</a>
</div>

Passen Sie in einer Blazor WebAssembly-App die Darstellung in der wwwroot/index.html-Datei an:

<div id="blazor-error-ui" data-nosnippet>
    An unhandled error has occurred.
    <a href="" class="reload">Reload</a>
    <a class="dismiss">🗙</a>
</div>

Das blazor-error-ui-Element wird normalerweise ausgeblendet, weil der display: none-Stil der blazor-error-ui-CSS-Klasse im automatisch generierten Stylesheet der App vorhanden ist. Wenn ein Fehler auftritt, wird display: block vom Framework auf das Element angewendet.

Das blazor-error-ui-Element ist normalerweise ausgeblendet, weil der display: none-Stil der blazor-error-ui-CSS-Klasse im Stylesheet der Website (im Ordner wwwroot/css) vorhanden ist. Wenn ein Fehler auftritt, wird display: block vom Framework auf das Element angewendet.

Detaillierte Leitungsfehler

Dieser Abschnitt gilt für Blazor-Web-Apps, die über eine Leitung betrieben werden.

Dieser Abschnitt gilt für Blazor Server-Apps.

Clientseitige Fehlermeldungen enthalten weder die Aufrufliste noch Details zur Fehlerursache, Serverprotokolle hingegen schon. Zu Entwicklungszwecken können vertrauliche Informationen zu Leitungsfehlern für den Client verfügbar gemacht werden, indem Sie detaillierte Fehlermeldungen aktivieren.

Legen Sie CircuitOptions.DetailedErrors auf true fest. Weitere Informationen und ein Beispiel finden Sie unter Leitfaden zu BlazorSignalR in ASP.NET Core.

Eine Alternative zum Festlegen von CircuitOptions.DetailedErrors besteht darin, den Konfigurationsschlüssel DetailedErrors in der Einstellungsdatei der Development-Umgebung der App (appsettings.Development.json) auf true festzulegen. Legen Sie außerdem die serverseitige SignalR-Protokollierung (Microsoft.AspNetCore.SignalR) zur detaillierten Protokollierung von SignalR auf Debug oder Trace fest.

appsettings.Development.json:

{
  "DetailedErrors": true,
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information",
      "Microsoft.AspNetCore.SignalR": "Debug"
    }
  }
}

Der Konfigurationsschlüssel DetailedErrors kann auch auf true festgelegt werden, indem auf Development/Staging-Umgebungsservern oder auf dem lokalen System die ASPNETCORE_DETAILEDERRORS-Umgebungsvariable mit dem Wert true verwendet wird.

Warnung

Vermeiden Sie es grundsätzlich, Fehlerinformationen für Internetclients verfügbar zu machen. Dies stellt ein Sicherheitsrisiko dar.

Detaillierte Fehler für Razor serverseitiges Rendern von Komponenten

Dieser Abschnitt gilt für Blazor-Web-Apps.

Verwenden Sie die RazorComponentsServiceOptions.DetailedErrors Option, um die Erstellung detaillierter Informationen zu Fehlern für das serverseitige Rendern von Razor Komponenten zu steuern. Der Standardwert ist false.

Im folgenden Beispiel werden detaillierte Fehler aktiviert:

builder.Services.AddRazorComponents(options => 
    options.DetailedErrors = builder.Environment.IsDevelopment());

Warnung

Aktivieren Sie nur detaillierte Fehler in der Development-Umgebung. Detaillierte Fehler können vertrauliche Informationen über die App enthalten, die Angreifer sich zunutze machen können.

Das vorangehende Beispiel bietet einen gewissen Grad an Sicherheit, indem der Wert von DetailedErrors basierend auf dem von IsDevelopment zurückgegebenen Wert festgelegt wird. Wenn sich die App in der Development-Umgebung befindet, wird DetailedErrors auf true festgelegt. Dieser Ansatz ist nicht absolut sicher, da es möglich ist, eine Produktions-App auf einem öffentlichen Server in der Development-Umgebung zu hosten.

Behandeln von Ausnahmefehlern in Entwicklercode

Damit die Ausführung einer App nach einem Fehler fortgesetzt werden kann, muss die App eine Fehlerbehandlungslogik enthalten. In späteren Abschnitten dieses Artikels werden mögliche Quellen für Ausnahmefehler beschrieben.

Rendern Sie in einer Produktionsumgebung keine Ausnahmemeldungen des Frameworks oder Stapelüberwachungen in der Benutzeroberfläche. Durch Rendern von Ausnahmemeldungen oder Stapelüberwachungen kann Folgendes geschehen:

  • Vertrauliche Informationen werden gegenüber Endbenutzern offengelegt.
  • Böswilligen Benutzern wird geholfen, Schwachstellen in einer App zu erkennen, die die Sicherheit von Server, App oder Netzwerk beeinträchtigen können.

Ausnahmefehler für Leitungen

Dieser Abschnitt gilt für serverseitige Apps, die über eine Verbindung betrieben werden.

Razor-Komponenten mit aktivierter Serverinteraktivität sind auf dem Server zustandsbehaftet. Während die Benutzer*innen mit der Komponente auf dem Server interagieren, unterhalten sie eine Verbindung mit dem Server, die als Leitung bezeichnet wird. Die Leitung enthält aktive Instanzen von Komponenten und weist zahlreiche andere Aspekte zum Zustand auf wie:

  • Die zuletzt gerenderte Ausgabe von Komponenten
  • Die aktuellen Delegate zur Ereignisbehandlung, die durch clientseitige Ereignisse ausgelöst werden können

Wenn ein Benutzer die App in mehreren Registerkarten eines Browsers öffnet, werden mehrere unabhängige Leitungen erstellt.

Die meisten Ausnahmefehler werden von Blazor als für die Leitung schwerwiegende Fehler behandelt. Wenn eine Leitung aufgrund eines Ausnahmefehlers beendet wird, kann der Benutzer nur dann mit der App weiter interagieren, wenn die Seite nochmals geladen und so eine neue Leitung erstellt wird. Leitungen außerhalb der beendeten Leitung, bei denen es sich um Leitungen für andere Benutzer oder andere Browserregisterkarten handelt, sind davon nicht betroffen. Dieses Szenario ähnelt einer Desktop-App, die abstürzt. Die abgestürzte App muss neu gestartet werden, aber andere Apps sind nicht betroffen.

Eine Leitung wird durch das Framework beendet, wenn aus folgenden Gründen ein Ausnahmefehler auftritt:

  • Bei einem Ausnahmefehler wird die Leitung häufig in einen nicht definierten Zustand versetzt.
  • Nach einem Ausnahmefehler kann ein normales Funktionieren der App nicht mehr sichergestellt werden.
  • Wenn die Leitung weiter in einem nicht definierten Zustand bestehen bleibt, können für die App Sicherheitsrisiken bestehen.

Globale Ausnahmebehandlung

Informationen zur globalen Ausnahmebehandlung finden Sie in den folgenden Abschnitten:

Fehlergrenzen

Fehlergrenzen bieten eine gut geeignete Möglichkeit für die Behandlung von Ausnahmen. Die Komponente ErrorBoundary:

  • Rendert den untergeordneten Inhalt, wenn kein Fehler aufgetreten ist.
  • Rendert die Fehleroberfläche, wenn eine nicht behandelte Ausnahme ausgelöst wird.

Zum Definieren einer Fehlergrenze verwenden Sie die ErrorBoundary-Komponente, vorhandenen Inhalt zu umschließen. Die App funktioniert weiterhin normal, die Fehlergrenze behandelt aber nicht behandelte Ausnahmen.

<ErrorBoundary>
    ...
</ErrorBoundary>

Um eine Fehlergrenze global zu implementieren, fügen Sie die Grenze um den Textinhalt des Hauptlayouts der App hinzu.

In MainLayout.razor:

<article class="content px-4">
    <ErrorBoundary>
        @Body
    </ErrorBoundary>
</article>

In Blazor-Web-Apps, bei denen die Fehlergrenze nur auf eine statische MainLayout-Komponente angewendet wird, ist die Grenze nur während des statischen serverseitigen Renderings (statisches SSR) aktiv. Die Grenze wird nicht aktiviert, nur weil eine Komponente weiter unten in der Komponentenhierarchie interaktiv ist. Um die Interaktivität für die Komponente MainLayout und die übrigen Komponenten weiter unten in der Komponentenhierarchie weitgehend zu aktivieren, aktivieren Sie interaktives Rendering für die Komponenteninstanzen HeadOutlet und Routes in der Komponente App (Components/App.razor). Im folgenden Beispiel wird der interaktive Serverrendermodus (InteractiveServer) verwendet:

<HeadOutlet @rendermode="InteractiveServer" />

...

<Routes @rendermode="InteractiveServer" />

Wenn Sie die Serverinteraktivität in der gesamten App aus der Routes-Komponente nicht aktivieren möchten, platzieren Sie die Fehlergrenze weiter unten in der Komponentenhierarchie. Platzieren Sie beispielsweise die Fehlergrenze um Markup in einzelnen Komponenten, die Interaktivität aktivieren, nicht im Hauptlayout der App. Unabhängig von der Position der Fehlergrenze sollten Sie folgende wichtige Konzepte berücksichtigen:

  • Wenn die Fehlergrenze nicht interaktiv ist, kann sie nur während des statischen Renderings auf dem Server aktiviert werden. Beispielsweise kann die Grenze aktiviert werden, wenn ein Fehler in der Lebenszyklusmethode einer Komponente ausgelöst wird.
  • Wenn die Fehlergrenze interaktiv ist, kann sie für interaktive, serverseitig gerenderte Komponenten aktiviert werden, die sie umschließt.

Betrachten Sie das folgende Beispiel, in dem die Counter-Komponente eine Ausnahme auslöst, wenn die Anzahl größer fünf wird.

In Counter.razor:

private void IncrementCount()
{
    currentCount++;

    if (currentCount > 5)
    {
        throw new InvalidOperationException("Current count is too big!");
    }
}

Wenn die nicht behandelte Ausnahme für currentCount größer fünf ausgelöst wird, gilt:

  • Der Fehler wird normal protokolliert (System.InvalidOperationException: Current count is too big!).
  • Die ausgelöste Ausnahme wird von der Fehlergrenze verarbeitet.
  • Die Fehlerbenutzeroberfläche wird durch die Fehlergrenze mit der folgenden Standardfehlermeldung gerendert: An error has occurred.

Standardmäßig rendert die ErrorBoundary-Komponente für den Fehlerinhalt ein leeres <div>-Element mit der CSS-Klasse blazor-error-boundary. Farben, Text und Symbol für die Standardbenutzeroberfläche werden über die CSS im Stylesheet der App im wwwroot-Ordner definiert, sodass Sie die Fehlerbenutzeroberfläche beliebig anpassen können.

Ändern Sie den Standardfehlerinhalt, indem Sie die ErrorContent-Eigenschaft festlegen:

<ErrorBoundary>
    <ChildContent>
        @Body
    </ChildContent>
    <ErrorContent>
        <p class="errorUI">😈 A rotten gremlin got us. Sorry!</p>
    </ErrorContent>
</ErrorBoundary>

Da die Fehlergrenze in den vorherigen Beispielen im Layout definiert ist, wird die Fehlerbenutzeroberfläche unabhängig davon angezeigt, zu welcher Seite die Benutzer*innen nach Auftreten des Fehlers navigieren. In den meisten Szenarien wird empfohlen, einen engen Bereich für die Fehlergrenze festzulegen. Wenn Sie den Bereich für die Fehlergrenze weit festlegen, können Sie sie bei nachfolgenden Seitennavigationsereignissen auf einen fehlerfreien Zustand zurücksetzen, indem Sie die Recover-Methode der Fehlergrenze aufrufen.

In MainLayout.razor:

...

<ErrorBoundary @ref="errorBoundary">
    @Body
</ErrorBoundary>

...

@code {
    private ErrorBoundary? errorBoundary;

    protected override void OnParametersSet()
    {
        errorBoundary?.Recover();
    }
}

Zur Vermeidung einer Endlosschleife, bei der die Wiederherstellung eine Komponente lediglich neu rendert und diese den Fehler erneut auslöst, sollten Sie Recover nicht aus der Renderinglogik aufrufen. Rufen Sie Recover nur in diesen Fällen auf:

  • Die Benutzer*innen zeigen durch Ausführung einer Benutzeroberflächengeste (z. B. Auswahl einer Schaltfläche) an, dass sie einen Vorgang wiederholen möchten, oder die Benutzer*innen navigieren zu einer neuen Komponente.
  • Die Ausnahme wird auch durch zusätzliche Logik beseitigt. Wenn die Komponente neu gerendert wird, tritt der Fehler nicht mehr auf.

Alternative globale Ausnahmebehandlung

Eine Alternative zur Verwendung von Fehlergrenzen (ErrorBoundary) besteht darin, eine benutzerdefinierte Fehlerkomponente als CascadingValue an untergeordnete Komponenten zu übergeben. Ein Vorteil der Verwendung einer Komponente gegenüber der Verwendung eines eingefügten Diensts oder der Implementierung einer benutzerdefinierten Protokollierung besteht darin, dass eine kaskadierenden Komponente Inhalte rendern und CSS-Stile anwenden kann, wenn ein Fehler auftritt.

Im folgenden Beispiel einer Error-Komponente werden Fehler lediglich protokolliert, Methoden der Komponente können Fehler jedoch in beliebiger Weise je nach Anforderungen der App verarbeiten, auch mithilfe mehrerer Fehlerverarbeitungsmethoden.

Error.razor:

@inject ILogger<Error> Logger

<CascadingValue Value="this">
    @ChildContent
</CascadingValue>

@code {
    [Parameter]
    public RenderFragment? ChildContent { get; set; }

    public void ProcessError(Exception ex)
    {
        Logger.LogError("Error:ProcessError - Type: {Type} Message: {Message}", 
            ex.GetType(), ex.Message);

        // Call StateHasChanged if ProcessError directly participates in 
        // rendering. If ProcessError only logs or records the error,
        // there's no need to call StateHasChanged.
        //StateHasChanged();
    }
}

Hinweis

Weitere Informationen zu RenderFragment finden Sie unter ASP.NET Core Razor Komponenten.

Umschließen Sie in der Routes-Komponente die Router-Komponente (<Router>...</Router>) mit der Error-Komponente. Dies erlaubt der Error-Komponente eine Kaskadierung an beliebige Komponenten der App, wobei die Error-Komponente als CascadingParameter empfangen wird.

In Routes.razor:

<Error>
    <Router ...>
        ...
    </Router>
</Error>

Umschließen Sie in der App-Komponente die Router-Komponente (<Router>...</Router>) mit der Error-Komponente. Dies erlaubt der Error-Komponente eine Kaskadierung an beliebige Komponenten der App, wobei die Error-Komponente als CascadingParameter empfangen wird.

In App.razor:

<Error>
    <Router ...>
        ...
    </Router>
</Error>

So verarbeiten Sie Fehler in einer-Komponente:

  • Legen Sie die Error-Komponente im @code-Block als CascadingParameter fest: Fügen Sie in einer Counter-Beispielkomponente in einer App, die auf einer Blazor-Projektvorlage basiert, die folgende Error-Eigenschaft hinzu:

    [CascadingParameter]
    public Error? Error { get; set; }
    
  • Rufen Sie eine Fehlerverarbeitungsmethode mit einem entsprechenden Ausnahmetyp in einem beliebigen catch-Block auf. Die Error-Komponente aus dem Beispiel verfügt nur über eine einzige ProcessError-Methode, die Fehlerverarbeitungskomponente kann jedoch eine beliebige Anzahl von Fehlerverarbeitungsmethoden bereitstellen, um Anforderungen an eine alternative Fehlerverarbeitung für die gesamte App zu ermöglichen. Im folgenden Beispiel für eine Counter-Komponente wird eine Ausnahme ausgelöst und abgefangen, wenn die Anzahl größer als fünf ist:

    @code {
        private int currentCount = 0;
    
        [CascadingParameter]
        public Error? Error { get; set; }
    
        private void IncrementCount()
        {
            try
            {
                currentCount++;
    
                if (currentCount > 5)
                {
                    throw new InvalidOperationException("Current count is over five!");
                }
            }
            catch (Exception ex)
            {
                Error?.ProcessError(ex);
            }
        }
    }
    

Mithilfe der vorherigen Error-Komponente mit den vorherigen Änderungen, die an einer Counter-Komponente vorgenommen wurden, gibt die Konsole mit den Entwicklertools des Browsers den abgefangenen, protokollierten Fehler an:

fail: {COMPONENT NAMESPACE}.Error[0]
Error:ProcessError - Type: System.InvalidOperationException Message: Current count is over five!

Wenn die ProcessError-Methode direkt an einem Rendering beteiligt ist, z. B. wenn eine benutzerdefinierte Fehlermeldungsleiste angezeigt wird oder die CSS-Stile der gerenderten Elemente geändert werden, wird StateHasChanged am Ende der ProcessErrors-Methode aufgerufen, um die Benutzeroberfläche neu zu rendern.

Da bei den Ansätzen in diesem Abschnitt Fehler mit einer try-catch-Anweisung behandelt werden, wird die SignalR-Verbindung einer App zwischen Client und Server nicht getrennt, wenn ein Fehler auftritt, und die Leitung wird aufrechterhalten. Andere nicht behandelte Ausnahmefehler bleiben für eine Leitung schwerwiegend. Weitere Informationen finden Sie im vorherigen Abschnitt, in dem erläutert wird, wie eine Leitung auf Ausnahmefehler reagiert.

Eine App kann eine Fehlerverarbeitungskomponente als kaskadierenden Wert verwenden, um Fehler zentral zu verarbeiten.

Die folgende Error-Komponente übergibt sich selbst als CascadingValue an untergeordnete Komponenten. Im folgenden Beispiel wird der Fehler lediglich protokolliert, Methoden der Komponente können Fehler jedoch in beliebiger Weise je nach Anforderungen der App verarbeiten, auch mithilfe mehrerer Fehlerverarbeitungsmethoden. Ein Vorteil der Verwendung einer Komponente gegenüber der Verwendung eines eingefügten Diensts oder der Implementierung einer benutzerdefinierten Protokollierung besteht darin, dass eine kaskadierenden Komponente Inhalte rendern und CSS-Stile anwenden kann, wenn ein Fehler auftritt.

Error.razor:

@using Microsoft.Extensions.Logging
@inject ILogger<Error> Logger

<CascadingValue Value="this">
    @ChildContent
</CascadingValue>

@code {
    [Parameter]
    public RenderFragment ChildContent { get; set; }

    public void ProcessError(Exception ex)
    {
        Logger.LogError("Error:ProcessError - Type: {Type} Message: {Message}", 
            ex.GetType(), ex.Message);
    }
}

Hinweis

Weitere Informationen zu RenderFragment finden Sie unter ASP.NET Core Razor Komponenten.

Erstellen Sie in der App-Komponente mit der Error-Komponente einen Wrapper für die Router-Komponente. Dies erlaubt der Error-Komponente eine Kaskadierung an beliebige Komponenten der App, wobei die Error-Komponente als CascadingParameter empfangen wird.

App.razor:

<Error>
    <Router ...>
        ...
    </Router>
</Error>

So verarbeiten Sie Fehler in einer-Komponente:

  • Legen Sie die Error-Komponente im @code-Block als CascadingParameter fest:

    [CascadingParameter]
    public Error Error { get; set; }
    
  • Rufen Sie eine Fehlerverarbeitungsmethode mit einem entsprechenden Ausnahmetyp in einem beliebigen catch-Block auf. Die Error-Komponente aus dem Beispiel verfügt nur über eine einzige ProcessError-Methode, die Fehlerverarbeitungskomponente kann jedoch eine beliebige Anzahl von Fehlerverarbeitungsmethoden bereitstellen, um Anforderungen an eine alternative Fehlerverarbeitung für die gesamte App zu ermöglichen.

    try
    {
        ...
    }
    catch (Exception ex)
    {
        Error.ProcessError(ex);
    }
    

Bei Verwendung der Error-Komponente und der ProcessError-Methode aus dem vorherigen Beispiel wird in Konsole mit den Entwicklertools des Browsers der aufgefangene protokollierte Fehler angegeben:

Fehler: BlazorSample.Shared.Error[0] Error:ProcessError – Typ: System.NullReferenceException Meldung: Objektverweis nicht auf eine Instanz eines Objekts festgelegt.

Wenn die ProcessError-Methode direkt an einem Rendering beteiligt ist, z. B. wenn eine benutzerdefinierte Fehlermeldungsleiste angezeigt oder die CSS-Stile der gerenderten Elemente geändert werden, wird StateHasChanged am Ende der ProcessErrors-Methode aufgerufen, um die Benutzeroberfläche zu rendern.

Da bei den Ansätzen in diesem Abschnitt Fehler mit einer try-catch-Anweisung behandelt werden, wird die SignalR-Verbindung einer Blazor-App zwischen Client und Server nicht getrennt, wenn ein Fehler auftritt, und die Leitung wird aufrechterhalten. Unbehandelte Ausnahmen führen zu einem schwerwiegenden Leitungsfehler. Weitere Informationen finden Sie im vorherigen Abschnitt, in dem erläutert wird, wie eine Leitung auf Ausnahmefehler reagiert.

Protokollieren von Fehlern bei einem permanenten Anbieter

Im Fall eines Ausnahmefehlers wird die Ausnahme in den im Dienstcontainer konfiguriertenILogger-Instanzen protokolliert. Blazor-Apps protokollieren standardmäßig in die Konsolenausgabe beim Konsolenprotokollierungsanbieter. Überlegen Sie, ob Sie die Protokollierung an einem Speicherort auf dem Server (oder einer Back-End-Web-API für clientseitige Apps) mit einem Anbieter durchführen, der die Protokollgröße und die Protokollrotation verwaltet. Alternativ kann die App einen APM-Dienst (Application Performance Management) verwenden, z. B. Azure Application Insights (Azure Monitor).

Hinweis

Native Application Insights-Features für die Unterstützung clientseitiger Apps und die native Unterstützung des Blazor-Frameworks für Google Analytics werden möglicherweise in zukünftigen Releases dieser Technologien zur Verfügung gestellt. Weitere Informationen finden Sie unter Support App Insights in Blazor WASM Client Side (microsoft/ApplicationInsights-dotnet #2143) und Web analytics and diagnostics (enthält Links zu Implementierungen der Community) (dotnet/aspnetcore #5461). In der Zwischenzeit kann eine clientseitige App das Application Insights JavaScript SDK mit JSInterop verwenden, um Fehler aus einer clientseitigen App direkt in Application Insights zu protokollieren.

Während der Entwicklung in einer Blazor-App, die über eine Leitung betrieben wird, sendet die App zur Unterstützung des Debuggings in der Regel alle Ausnahmedetails an die Konsole des Browsers. In der Produktionsumgebung werden keine ausführlichen Fehler an Clients gesendet, die vollständigen Details der Ausnahme werden jedoch auf dem Server protokolliert.

Sie müssen entscheiden, welche Vorfälle protokolliert werden sollen. Zudem müssen Sie den Schweregrad für protokollierte Vorfälle festlegen. Feindliche Benutzer können Fehler möglicherweise absichtlich auslöst. Protokollieren Sie beispielsweise keinen Vorfall aus einem Fehler, bei dem eine unbekannte ProductId in der URL einer Komponente angegeben wurde, über die Produktdetails angezeigt werden. Nicht alle Fehler sollten als zu protokollierende Vorfälle behandelt werden.

Weitere Informationen finden Sie in den folgenden Artikeln:

‡Betrifft serverseitige Blazor-Apps und andere serverseitige ASP.NET Core-Apps, die als Web-API-Back-End-Apps für Blazor dienen. Clientseitige Apps können Fehlerinformationen auf dem Client abfangen und an eine Web-API senden, die die Fehlerinformationen in einem persistenten Protokollierungsanbieter protokolliert.

Im Fall eines Ausnahmefehlers wird die Ausnahme in den im Dienstcontainer konfiguriertenILogger-Instanzen protokolliert. Blazor-Apps protokollieren standardmäßig in die Konsolenausgabe beim Konsolenprotokollierungsanbieter. Sie sollten einen dauerhaften Speicherort auf dem Server für die Protokollierung verwenden, indem Sie Fehlerinformationen an eine Back-End-Web-API senden, die einen Protokollierungsanbieter mit Verwaltung der Protokollgröße und Protokollrotation verwendet. Alternativ kann die Back-End-Web-API-App einen APM-Dienst (Application Performance Management) verwenden, z. B. Azure Application Insights (Azure Monitor)†, um Fehlerinformationen aufzuzeichnen, die von Clients empfangen werden.

Sie müssen entscheiden, welche Vorfälle protokolliert werden sollen. Zudem müssen Sie den Schweregrad für protokollierte Vorfälle festlegen. Feindliche Benutzer können Fehler möglicherweise absichtlich auslöst. Protokollieren Sie beispielsweise keinen Vorfall aus einem Fehler, bei dem eine unbekannte ProductId in der URL einer Komponente angegeben wurde, über die Produktdetails angezeigt werden. Nicht alle Fehler sollten als zu protokollierende Vorfälle behandelt werden.

Weitere Informationen finden Sie in den folgenden Artikeln:

†Native Application Insights-Features für die Unterstützung clientseitiger Apps und die native Unterstützung des Blazor-Frameworks für Google Analytics werden möglicherweise in zukünftigen Releases dieser Technologien zur Verfügung gestellt. Weitere Informationen finden Sie unter Support App Insights in Blazor WASM Client Side (microsoft/ApplicationInsights-dotnet #2143) und Web analytics and diagnostics (enthält Links zu Implementierungen der Community) (dotnet/aspnetcore #5461). In der Zwischenzeit kann eine clientseitige App das Application Insights JavaScript SDK mit JSInterop verwenden, um Fehler aus einer clientseitigen App direkt in Application Insights zu protokollieren.

‡Betrifft serverseitige ASP.NET Core-Apps, die als Web-API-Back-End-Apps für Blazor-Apps dienen. Clientseitige Apps fangen Fehlerinformationen ab und senden sie an eine Web-API, die die Fehlerinformationen in einem persistenten Protokollierungsanbieter protokolliert.

Stellen, an denen Fehler auftreten können

Frameworks und App-Code können nicht behandelte Ausnahmen an einem der folgenden Orte auslösen, die in den folgenden Abschnitten dieses Artikels erläutert werden:

Komponenteninstanziierung

Wenn durch Blazor eine Instanz einer Komponente erstellt wird:

  • Wird der Konstruktor der Komponente aufgerufen.
  • Werden die Konstruktoren von Abhängigkeitsinjektionsdiensten aufgerufen, die über die @inject-Anweisung oder das [Inject]-Attribut für den Konstruktor der Komponente bereitgestellt werden.

Ein Fehler in einem ausgeführten Konstruktor oder Setter für eine beliebige [Inject]-Eigenschaft führt zu einer nicht behandelten Ausnahme und verhindert ein Instanziieren der Komponente durch das Framework. Wenn die App über eine Leitung betrieben wird, schlägt die Leitung fehl. Wenn eine Konstruktorlogik Ausnahmen auslösen kann, muss die App die Ausnahmen mithilfe einer try-catch-Anweisung mit Fehlerbehandlung und Fehlerprotokollierung abfangen.

Lebenszyklusmethoden

Während der Lebensdauer einer Komponente ruft BlazorLebenszyklusmethoden auf. Wenn eine Lebenszyklusmethode synchron oder asynchron eine Ausnahme auslöst, ist die Ausnahme für eine -Leitung schwerwiegend. Damit Komponenten Fehler in Lebenszyklusmethoden behandeln können, fügen Sie eine Fehlerbehandlungslogik hinzu.

Im folgenden Beispiel, in dem OnParametersSetAsync eine Methode zum Aufrufen eines Produkts aufruft:

  • Wird eine Ausnahme, die in der ProductRepository.GetProductByIdAsync-Methode ausgelöst wird, durch eine try-catch-Anweisung behandelt.
  • Wenn der catch-Block ausgeführt wird:
    • wird loadFailed auf true festgelegt, sodass dem Benutzer eine Fehlermeldung angezeigt wird.
    • wird der Fehler protokolliert.
@page "/product-details/{ProductId:int?}"
@inject ILogger<ProductDetails> Logger
@inject IProductRepository Product

<PageTitle>Product Details</PageTitle>

<h1>Product Details Example</h1>

@if (details != null)
{
    <h2>@details.ProductName</h2>
    <p>
        @details.Description
        <a href="@details.Url">Company Link</a>
    </p>
    
}
else if (loadFailed)
{
    <h1>Sorry, we could not load this product due to an error.</h1>
}
else
{
    <h1>Loading...</h1>
}

@code {
    private ProductDetail? details;
    private bool loadFailed;

    [Parameter]
    public int ProductId { get; set; }

    protected override async Task OnParametersSetAsync()
    {
        try
        {
            loadFailed = false;

            // Reset details to null to display the loading indicator
            details = null;

            details = await Product.GetProductByIdAsync(ProductId);
        }
        catch (Exception ex)
        {
            loadFailed = true;
            Logger.LogWarning(ex, "Failed to load product {ProductId}", ProductId);
        }
    }

    public class ProductDetail
    {
        public string? ProductName { get; set; }
        public string? Description { get; set; }
        public string? Url { get; set; }
    }

    /*
    * Register the service in Program.cs:
    * using static BlazorSample.Components.Pages.ProductDetails;
    * builder.Services.AddScoped<IProductRepository, ProductRepository>();
    */

    public interface IProductRepository
    {
        public Task<ProductDetail> GetProductByIdAsync(int id);
    }

    public class ProductRepository : IProductRepository
    {
        public Task<ProductDetail> GetProductByIdAsync(int id)
        {
            return Task.FromResult(
                new ProductDetail()
                {
                    ProductName = "Flowbee ",
                    Description = "The Revolutionary Haircutting System You've Come to Love!",
                    Url = "https://flowbee.com/"
                });
        }
    }
}
@page "/product-details/{ProductId:int}"
@using Microsoft.Extensions.Logging
@inject ILogger<ProductDetails> Logger
@inject IProductRepository ProductRepository

@if (details != null)
{
    <h1>@details.ProductName</h1>
    <p>@details.Description</p>
}
else if (loadFailed)
{
    <h1>Sorry, we could not load this product due to an error.</h1>
}
else
{
    <h1>Loading...</h1>
}

@code {
    private ProductDetail? details;
    private bool loadFailed;

    [Parameter]
    public int ProductId { get; set; }

    protected override async Task OnParametersSetAsync()
    {
        try
        {
            loadFailed = false;

            // Reset details to null to display the loading indicator
            details = null;

            details = await ProductRepository.GetProductByIdAsync(ProductId);
        }
        catch (Exception ex)
        {
            loadFailed = true;
            Logger.LogWarning(ex, "Failed to load product {ProductId}", ProductId);
        }
    }

    public class ProductDetail
    {
        public string? ProductName { get; set; }
        public string? Description { get; set; }
    }

    public interface IProductRepository
    {
        public Task<ProductDetail> GetProductByIdAsync(int id);
    }
}
@page "/product-details/{ProductId:int}"
@using Microsoft.Extensions.Logging
@inject ILogger<ProductDetails> Logger
@inject IProductRepository ProductRepository

@if (details != null)
{
    <h1>@details.ProductName</h1>
    <p>@details.Description</p>
}
else if (loadFailed)
{
    <h1>Sorry, we could not load this product due to an error.</h1>
}
else
{
    <h1>Loading...</h1>
}

@code {
    private ProductDetail? details;
    private bool loadFailed;

    [Parameter]
    public int ProductId { get; set; }

    protected override async Task OnParametersSetAsync()
    {
        try
        {
            loadFailed = false;

            // Reset details to null to display the loading indicator
            details = null;

            details = await ProductRepository.GetProductByIdAsync(ProductId);
        }
        catch (Exception ex)
        {
            loadFailed = true;
            Logger.LogWarning(ex, "Failed to load product {ProductId}", ProductId);
        }
    }

    public class ProductDetail
    {
        public string? ProductName { get; set; }
        public string? Description { get; set; }
    }

    public interface IProductRepository
    {
        public Task<ProductDetail> GetProductByIdAsync(int id);
    }
}
@page "/product-details/{ProductId:int}"
@using Microsoft.Extensions.Logging
@inject ILogger<ProductDetails> Logger
@inject IProductRepository ProductRepository

@if (details != null)
{
    <h1>@details.ProductName</h1>
    <p>@details.Description</p>
}
else if (loadFailed)
{
    <h1>Sorry, we could not load this product due to an error.</h1>
}
else
{
    <h1>Loading...</h1>
}

@code {
    private ProductDetail details;
    private bool loadFailed;

    [Parameter]
    public int ProductId { get; set; }

    protected override async Task OnParametersSetAsync()
    {
        try
        {
            loadFailed = false;

            // Reset details to null to display the loading indicator
            details = null;

            details = await ProductRepository.GetProductByIdAsync(ProductId);
        }
        catch (Exception ex)
        {
            loadFailed = true;
            Logger.LogWarning(ex, "Failed to load product {ProductId}", ProductId);
        }
    }

    public class ProductDetail
    {
        public string ProductName { get; set; }
        public string Description { get; set; }
    }

    public interface IProductRepository
    {
        public Task<ProductDetail> GetProductByIdAsync(int id);
    }
}
@page "/product-details/{ProductId:int}"
@using Microsoft.Extensions.Logging
@inject ILogger<ProductDetails> Logger
@inject IProductRepository ProductRepository

@if (details != null)
{
    <h1>@details.ProductName</h1>
    <p>@details.Description</p>
}
else if (loadFailed)
{
    <h1>Sorry, we could not load this product due to an error.</h1>
}
else
{
    <h1>Loading...</h1>
}

@code {
    private ProductDetail details;
    private bool loadFailed;

    [Parameter]
    public int ProductId { get; set; }

    protected override async Task OnParametersSetAsync()
    {
        try
        {
            loadFailed = false;

            // Reset details to null to display the loading indicator
            details = null;

            details = await ProductRepository.GetProductByIdAsync(ProductId);
        }
        catch (Exception ex)
        {
            loadFailed = true;
            Logger.LogWarning(ex, "Failed to load product {ProductId}", ProductId);
        }
    }

    public class ProductDetail
    {
        public string ProductName { get; set; }
        public string Description { get; set; }
    }

    public interface IProductRepository
    {
        public Task<ProductDetail> GetProductByIdAsync(int id);
    }
}

Renderinglogik

Das deklarative Markup in einer Razor-Komponentendatei (.razor) wird in eine C#-Methode namens BuildRenderTree kompiliert. Beim Rendern einer Komponente wird von BuildRenderTree eine Datenstruktur ausgeführt und erstellt, die Elemente, Text und untergeordnete Komponenten der gerenderten Komponente beschreibt.

Die Renderinglogik kann eine Ausnahme auslösen. Ein Beispiel für dieses Szenario tritt auf, wenn @someObject.PropertyName ausgewertet wird, @someObject jedoch null ist. Bei Blazor-Apps, die über eine Leitung betrieben werden, ist ein von der Renderinglogik ausgelöster Ausnahmefehler für die Leitung der App schwerwiegend.

Um in einer Renderinglogik eine NullReferenceException zu vermeiden, prüfen Sie vor dem Zugriff auf die entsprechenden Member, ob ein null-Objekt vorhanden ist. Im folgenden Beispiel wird auf die person.Address-Eigenschaften nicht zugegriffen, wenn person.Addressnull ist:

@if (person.Address != null)
{
    <div>@person.Address.Line1</div>
    <div>@person.Address.Line2</div>
    <div>@person.Address.City</div>
    <div>@person.Address.Country</div>
}

Für den obigen Code wird angenommen, dass person nicht null ist. Häufig wird durch die Codestruktur sichergestellt, dass ein Objekt zu dem Zeitpunkt vorhanden ist, zu dem die Komponente gerendert wird. In diesen Fällen muss nicht geprüft werden, ob null in der Renderinglogik vorhanden ist. Im vorigen Beispiel kann garantiert werden, dass person vorhanden ist, da person beim Instanziieren der Komponente erstellt wird, wie das folgende Beispiel veranschaulicht:

@code {
    private Person person = new();

    ...
}

Ereignishandler

Clientseitiger Code löst Aufrufe von C#-Code aus, wenn Ereignishandler mit folgenden Elementen erstellt werden:

  • @onclick
  • @onchange
  • Mit anderen @on...-Attributen
  • @bind

Der Ereignishandlercode löst in diesen Szenarios möglicherweise einen Ausnahmefehler aus.

Für den Fall, dass durch die App Code aufgerufen wird, der aus externen Gründen einen Fehler verursachen könnte, müssen Ausnahmen mithilfe einer try-catch-Anweisung mit Fehlerbehandlung und Fehlerprotokollierung abgefangen werden.

Wenn ein Ereignishandler einen nicht behandelten Ausnahmefehler auslöst (wenn beispielsweise bei einer Datenbankabfrage ein Fehler auftritt), der vom Entwicklercode nicht abgefangen und behandelt wird, geschieht Folgendes:

  • Das Framework protokolliert den Ausnahmefehler.
  • Bei Blazor-Apps, die über eine Leitung betrieben werden, ist die Ausnahme für die Leitung der App schwerwiegend.

Beseitigung von Komponenten

Eine Komponente kann von der Benutzeroberfläche entfernt werden, weil der Benutzer beispielsweise zu einer anderen Seite navigiert ist. Wenn eine Komponente, die System.IDisposable implementiert, von der Benutzeroberfläche entfernt wird, ruft das Framework die Dispose-Methode der Komponente auf.

Wenn die Dispose-Methode der Komponente einen Ausnahmefehler in einer Blazor-App auslöst, die über eine Leitung betrieben wird, ist die Ausnahme für die Leitung der App schwerwiegend.

Wenn die Logik zum Verwerfen Ausnahmen auslösen kann, sollte die App die Ausnahmen mit einer try-catch-Anweisung mit Fehlerbehandlung und Protokollierung abfangen.

Weitere Informationen zur Beseitigung von Komponenten finden Sie unter Lebenszyklus von Razor-Komponenten in ASP.NET Core.

JavaScript-Interoperabilität

IJSRuntime wird vom Blazor-Framework registriert. Mit IJSRuntime.InvokeAsync kann .NET-Code die JavaScript-Runtime (JS) im Browser des Benutzers asynchron aufrufen.

Die folgenden Bedingungen gelten für die Fehlerbehandlung mit InvokeAsync:

  • Wenn ein Aufruf von InvokeAsync synchron fehlschlägt, tritt eine .NET-Ausnahme auf. Ein Aufruf von InvokeAsync kann beispielsweise fehlschlagen, wenn die bereitgestellten Argumente nicht serialisiert werden können. Die Ausnahme muss vom Entwicklercode abgefangen werden. Wenn eine Ausnahme in einer Blazor-App, die über eine Leitung betrieben wird, nicht vom App-Code in einem Ereignishandler oder in der Lebenszyklusmethode einer Komponente behandelt wird, ist die resultierende Ausnahme für die Leitung der App schwerwiegend.
  • Wenn ein Aufruf von InvokeAsync asynchron fehlschlägt, schlägt die .NET Task fehl. Ein Aufruf von InvokeAsync kann beispielsweise fehlschlagen, wenn der Code auf JS-Seite eine Ausnahme auslöst oder eine Promise zurückgibt, die als rejected abgeschlossen wird. Die Ausnahme muss vom Entwicklercode abgefangen werden. Wenn Sie den await-Operator verwenden, sollten Sie in Erwägung ziehen, den Methodenaufruf mithilfe einer try-catch-Anweisung mit Fehlerbehandlung und Fehlerprotokollierung zu umschließen. Andernfalls führt der fehlerhafte Code in einer Blazor-App, die über eine Leitung betrieben wird, zu einem Ausnahmefehler, der für die Leitung der App schwerwiegend ist.
  • Ein Aufruf von InvokeAsync muss standardmäßig innerhalb eines bestimmten Zeitraums abgeschlossen werden, da es ansonsten für den Aufruf zu einem Timeout kommt. Der Standardwert für den Timeout beträgt eine Minute. Mit dem Zeitlimit wird der Code vor dem Verlust der Netzwerkkonnektivität oder vor JS-Code geschützt, der keine Abschlussmeldung sendet. Wenn beim Aufruf ein Timeout auftritt, schlägt die resultierende System.Threading.Tasks mit einer OperationCanceledExceptionfehl. Die Ausnahme wird abgefangen und mit Protokollierung verarbeitet.

Ähnlich kann JS-Code Aufrufe von .NET-Methoden einleiten, die vom [JSInvokable]-Attribut angegeben werden. Wenn diese .NET-Methoden einen Ausnahmefehler auslösen:

  • Bei Blazor-Apps, die über eine Leitung betrieben werden, ist die Ausnahme für die Leitung der App nicht schwerwiegend.
  • Die JS-seitige Element Promise wird abgelehnt.

Sie können Fehlerbehandlungscode auf der .NET-Seite oder JS-Seite des Methodenaufrufs verwenden.

Weitere Informationen finden Sie in den folgenden Artikeln:

Voarabrendering

Razor-Komponenten können vorab gerendert werden, sodass das gerenderte HTML-Markup als Teil der ursprünglichen HTTP-Benutzeranforderung zurückgegeben wird.

In einer Blazor-App, die über eine Leitung betrieben wird, funktioniert das Vorabrendering folgendermaßen:

  • Erstellen einer neuen Leitung für alle vorab gerenderten Komponenten, die Teil derselben Seite sind
  • Generieren des ursprünglichen HTML-Codes
  • Behandeln der Leitung als disconnected, bis der Browser des Benutzers eine SignalR-Verbindung zurück zum selben Server einrichtet. Wenn die Verbindung hergestellt wird, wird die Interaktivität in der Leitung fortgesetzt und das HTML-Markup der Komponenten wird aktualisiert.

Bei vorab gerenderten clientseitigen Komponenten funktioniert das Vorabrendering folgendermaßen:

  • Generieren des anfänglichen HTML-Codes auf dem Server für alle vorab gerenderten Komponenten, die Teil einer Seite sind.
  • Gestalten der Komponente auf dem Client als interaktiv, nachdem der Browser den kompilierten Code der App und die .NET-Runtime (sofern noch nicht geladen) im Hintergrund geladen hat.

Wenn von einer Komponente während des Vorabrenderns ein Ausnahmefehler beispielswiese während einer Lebenszyklusmethode oder in der Renderinglogik ausgelöst wird, gilt Folgendes:

  • Bei Blazor-Apps, die über eine Leitung betrieben werden, ist die Ausnahme für die Leitung schwerwiegend. Bei vorab gerenderten clientseitigen Komponenten verhindert die Ausnahme, dass die Komponente gerendert wird.
  • Die Ausnahme wird vom ComponentTagHelper in der Aufrufliste weiter oben ausgelöst.

Wenn das Prerendering unter normalen Umständen fehlschlägt, ist es nicht sinnvoll, mit dem Erstellen und Rendern der Komponente fortzufahren, da eine funktionierende Komponente nicht gerendert werden kann.

Wenn während des Prerenderings auftretende Fehler toleriert werden sollen, muss sich die Fehlerbehandlungslogik in einer Komponente befinden, die möglicherweise Ausnahmen auslöst. Verwenden Sie try-catch-Anweisungen mit Fehlerbehandlung und Fehlerprotokollierung. Statt das ComponentTagHelper in einer try-catch-Anweisung zu umschließen, fügen Sie eine Fehlerbehandlungslogik in die vom ComponentTagHelper gerenderte Komponente ein.

Erweiterte Szenarien

Rekursives Rendering

Komponenten können rekursiv geschachtelt sein. Dies ist nützlich, um rekursive Datenstrukturen darzustellen. So kann eine TreeNode-Komponente beispielsweise weitere TreeNode-Komponenten für die einzelnen untergeordneten Elemente des Knotens rendern.

Vermeiden Sie beim rekursiven Rendern Codemuster, die zu einer Endlosschleife führen:

  • Vermeiden Sie rekursives Rendering bei einer Datenstruktur, die einen Zyklus enthält. Rendern Sie beispielsweise keinen Strukturknoten, dessen untergeordnete Knoten sich selbst enthalten.
  • Erstellen Sie keine Layoutkette, die einen Zyklus enthält. Erstellen Sie beispielsweise kein Layout, das sein eigenes Layout ist.
  • Lassen Sie nicht zu, dass ein Endbenutzer Rekursionsinvarianten (Regeln) durch eine böswillige Dateneingabe oder JavaScript-Interoperabilitätsaufrufe verletzt.

Endlosschleifen durch Rendering:

  • sorgt dafür, dass der Renderingprozess unendlich fortgesetzt wird.
  • entspricht dem Erstellen einer nicht abgeschlossenen Schleife.

In diesen Szenarien schlägt Blazor fehl, und es wird in der Regel Folgendes versucht:

  • Unbegrenzt so viel CPU-Zeit wie vom Betriebssystem zulässig zu nutzen.
  • Eine unbegrenzte Menge an Arbeitsspeicher zu nutzen. Das Belegen einer unbegrenzte Menge an Arbeitsspeicher entspricht einem Szenario, bei dem eine nicht beendete Schleife einer Auflistung bei jeder Iteration Einträge hinzufügt.

Wenn Sie Muster mit Endlosrekursionen vermeiden möchten, müssen Sie sicherstellen, dass der Renderingcode geeignete Beendigungsbedingungen enthält.

Benutzerdefinierte Renderstrukturlogik

Die meisten Razor-Komponenten sind als Razor-Komponentendateien (.razor) implementiert und werden vom Framework kompiliert, um die Logik zu erstellen, die einen RenderTreeBuilder zum Rendern der Ausgabe verwendet. Ein Entwickler kann eine RenderTreeBuilder-Logik allerdings mit prozeduralem C#-Code manuell implementieren. Weitere Informationen finden Sie unter Fortgeschrittene Szenarios zu ASP.NET Core Blazor (Renderstrukturerstellung).

Warnung

Die Verwendung einer manuellen Buildlogik für die Renderstruktur gilt als erweitertes und unsicheres Szenario, das für die allgemeine Komponentenentwicklung nicht empfohlen wird.

Beim Schreiben von RenderTreeBuilder-Code muss der Entwickler die Richtigkeit des Codes garantieren. Der Entwickler muss beispielsweise Folgendes sicherstellen:

  • Aufrufe von OpenElement und CloseElement sind ordnungsgemäß ausgeglichen.
  • Attribute werden nur an den richtigen Stellen hinzugefügt.

Eine fehlerhafte Buildlogik für die Renderstruktur kann zu einem willkürlichen undefinierten Verhalten führen, u. a. zu Abstürzen, nicht mehr reagierenden Apps oder Servern und zu Sicherheitsrisiken.

Eine manuelle Buildlogik für die Renderstruktur ist genauso komplex und birgt dasselbe Maß an Gefahren wie das manuelle Schreiben von Assemblycode oder MSIL-Anweisungen (Microsoft Intermediate Language).

Zusätzliche Ressourcen

†Gilt für Back-End-Web-API-Apps in ASP.NET Core, die clientseitige Blazor-Apps für die Protokollierung verwenden.