Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Notitie
Dit is niet de nieuwste versie van dit artikel. Zie de .NET 9-versie van dit artikelvoor de huidige release.
Waarschuwing
Deze versie van ASP.NET Core wordt niet meer ondersteund. Zie de .NET- en .NET Core-ondersteuningsbeleidvoor meer informatie. Zie de .NET 9-versie van dit artikelvoor de huidige release.
Belangrijk
Deze informatie heeft betrekking op een pre-releaseproduct dat aanzienlijk kan worden gewijzigd voordat het commercieel wordt uitgebracht. Microsoft geeft geen garanties, uitdrukkelijk of impliciet, met betrekking tot de informatie die hier wordt verstrekt.
Zie de .NET 9-versie van dit artikelvoor de huidige release.
In dit artikel wordt beschreven hoe Blazor niet-verwerkte uitzonderingen beheert en hoe u apps ontwikkelt die fouten detecteren en afhandelen.
Gedetailleerde fouten tijdens de ontwikkeling
Wanneer een Blazor-app niet goed werkt tijdens de ontwikkeling, krijgt u gedetailleerde foutinformatie van de app om het probleem op te lossen. Wanneer er een fout optreedt, geven Blazor apps onderaan het scherm een lichtgele balk weer:
- Tijdens de ontwikkeling leidt de balk u naar de browserconsole, waar u de uitzondering kunt zien.
- In productie geeft de balk de gebruiker een bericht dat er een fout is opgetreden en wordt aangeraden de browser te vernieuwen.
De gebruikersinterface voor deze foutafhandelingservaring maakt deel uit van de Blazor projectsjablonen. Niet alle versies van de Blazor projectsjablonen maken gebruik van het kenmerk data-nosnippet
om browsers te signaleren dat de inhoud van de foutgebruikersinterface niet wordt opgeslagen, maar alle versies van de Blazor documentatie passen het kenmerk toe.
Pas in een Blazor Web Appde ervaring in het MainLayout
-onderdeel aan. Omdat de omgevings-taghelper (bijvoorbeeld <environment include="Production">...</environment>
) niet wordt ondersteund in Razor componenten, wordt in het volgende voorbeeld IHostEnvironment geïnjecteerd om foutmeldingen voor verschillende omgevingen te configureren.
Boven aan MainLayout.razor
:
@inject IHostEnvironment HostEnvironment
Maak of wijzig de Blazor fout-UI-markeringen:
<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>
Pas in een Blazor Server-app de ervaring in het Pages/_Host.cshtml
-bestand aan. In het volgende voorbeeld wordt de Environment Tag Helper gebruikt om foutberichten voor verschillende omgevingen te configureren.
Pas in een Blazor Server-app de ervaring in het Pages/_Layout.cshtml
-bestand aan. In het volgende voorbeeld wordt de Environment Tag Helper gebruikt om foutberichten voor verschillende omgevingen te configureren.
Pas in een Blazor Server-app de ervaring in het Pages/_Host.cshtml
-bestand aan. In het volgende voorbeeld wordt de Environment Tag Helper gebruikt om foutberichten voor verschillende omgevingen te configureren.
Maak of wijzig de Blazor fout-UI-markeringen:
<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>
Pas in een Blazor WebAssembly-app de ervaring in het wwwroot/index.html
-bestand aan:
<div id="blazor-error-ui" data-nosnippet>
An unhandled error has occurred.
<a href="" class="reload">Reload</a>
<a class="dismiss">🗙</a>
</div>
Het blazor-error-ui
-element wordt normaal gesproken verborgen vanwege de aanwezigheid van de display: none
stijl van de blazor-error-ui
CSS-klasse in het automatisch gegenereerde opmaakmodel van de app. Wanneer er een fout optreedt, past het framework display: block
toe op het element.
Het blazor-error-ui
element wordt normaal gesproken verborgen vanwege de aanwezigheid van de display: none
stijl van de blazor-error-ui
CSS-klasse in het opmaakmodel van de site in de wwwroot/css
map. Wanneer er een fout optreedt, past het framework display: block
toe op het element.
Gedetailleerde circuitfouten
Deze sectie is van toepassing op Blazor Web Appdie via een circuit werken.
Deze sectie is van toepassing op Blazor Server apps.
Fouten aan de clientzijde bevatten niet de aanroepstack en bevatten geen details over de oorzaak van de fout, maar serverlogboeken bevatten dergelijke informatie. Voor ontwikkelingsdoeleinden kan informatie over gevoelige circuitfouten beschikbaar worden gesteld aan de client door gedetailleerde fouten in te schakelen.
Stel CircuitOptions.DetailedErrors in op true
. Zie ASP.NET Core BlazorSignalR richtlijnenvoor meer informatie en een voorbeeld.
Een alternatief voor het instellen van CircuitOptions.DetailedErrors is het instellen van de DetailedErrors
configuratiesleutel op true
in het bestand met Development
omgevingsinstellingen van de app (appsettings.Development.json
). Stel daarnaast SignalR logboekregistratie aan de serverzijde in (Microsoft.AspNetCore.SignalR
) op Debug of Trace voor gedetailleerde SignalR logboekregistratie.
appsettings.Development.json
:
{
"DetailedErrors": true,
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information",
"Microsoft.AspNetCore.SignalR": "Debug"
}
}
}
De DetailedErrors-configuratiesleutel kan ook worden ingesteld op true
met behulp van de omgevingsvariabele ASPNETCORE_DETAILEDERRORS
met een waarde van true
op Development
/Staging
omgevingsservers of op uw lokale systeem.
Waarschuwing
Vermijd altijd het blootstellen van foutinformatie aan clients op internet, wat een beveiligingsrisico is.
Gedetailleerde fouten voor Razor component server-side rendering
Deze sectie is van toepassing op Blazor Web Apps.
Gebruik de RazorComponentsServiceOptions.DetailedErrors-optie om gedetailleerde informatie over fouten te regelen bij het server-side renderen van Razor componenten. De standaardwaarde is false
.
In het volgende voorbeeld worden gedetailleerde fouten weergegeven:
builder.Services.AddRazorComponents(options =>
options.DetailedErrors = builder.Environment.IsDevelopment());
Waarschuwing
Schakel alleen gedetailleerde fouten in de Development
-omgeving in. Gedetailleerde fouten kunnen gevoelige informatie bevatten over de app die kwaadwillende gebruikers kunnen gebruiken bij een aanval.
In het voorgaande voorbeeld wordt een zekere mate van veiligheid geboden door de waarde van DetailedErrors in te stellen op basis van de waarde die door IsDevelopmentwordt geretourneerd. Wanneer de app zich in de Development
-omgeving bevindt, wordt DetailedErrors ingesteld op true
. Deze aanpak is niet onfeilbaar omdat het mogelijk is om een productie-app te hosten op een openbare server in de Development
-omgeving.
Niet-verwerkte uitzonderingen in ontwikkelaarscode beheren
Als een app na een fout kan doorgaan, moet de app logica voor foutafhandeling hebben. In latere secties van dit artikel worden mogelijke bronnen van niet-verwerkte uitzonderingen beschreven.
Maak in productie geen framework-uitzonderingsberichten of stacktraceringen in de gebruikersinterface. Het weergeven van uitzonderingsberichten of stacktraces kan:
- Gevoelige informatie vrijgeven aan eindgebruikers.
- Een kwaadwillende gebruiker helpen zwakke plekken in een app te detecteren die de beveiliging van de app, server of netwerk kan in gevaar komen.
Niet-verwerkte uitzonderingen voor circuits
Deze sectie is van toepassing op apps aan de serverzijde die via een circuit worden uitgevoerd.
Onderdelen van Razor waarvoor server-interactiviteit is ingeschakeld, zijn statusbewust op de server. Terwijl gebruikers interactie hebben met het onderdeel op de server, onderhouden ze een verbinding met de server die bekend staat als een circuit. Het circuit bevat actieve componentinstanties, plus veel andere aspecten van de toestand, zoals:
- De meest recente weergegeven uitvoer van componenten.
- De huidige set gedelegeerden voor gebeurtenisafhandeling die kunnen worden geactiveerd door gebeurtenissen aan de clientzijde.
Als een gebruiker de app op meerdere browsertabbladen opent, maakt de gebruiker meerdere onafhankelijke circuits.
Blazor behandelt de meeste onverwerkte uitzonderingen als fataal voor het circuit waar ze voorkomen. Als een circuit wordt beëindigd vanwege een niet-verwerkte uitzondering, kan de gebruiker alleen met de app blijven werken door de pagina opnieuw te laden om een nieuw circuit te maken. Circuits buiten de circuits die worden beëindigd, die circuits zijn voor andere gebruikers of andere browsertabbladen, worden niet beïnvloed. Dit scenario is vergelijkbaar met een desktop-app die vastloopt. De vastgelopen app moet opnieuw worden opgestart, maar andere apps worden niet beïnvloed.
Het framework beëindigt een circuit wanneer een niet-verwerkte uitzondering plaatsvindt om de volgende redenen:
- Een niet-verwerkte uitzondering laat het circuit vaak in een ongedefinieerde toestand achter.
- De normale werking van de app kan niet worden gegarandeerd na een onverwerkte uitzondering.
- Beveiligingsproblemen kunnen in de app optreden als het circuit zich in een onbepaalde staat bevindt.
Algemene afhandeling van uitzonderingen
Zie de volgende secties voor benaderingen voor het wereldwijd verwerken van uitzonderingen:
- Foutgrenzen: van toepassing op alle Blazor-apps.
- Alternatieve algemene uitzonderingsafhandeling: van toepassing op Blazor Server, Blazor WebAssemblyen Blazor Web Apps (8,0 of hoger) die een globale interactieve weergavemodus aannemen.
Foutgrenzen
Foutgrenzen een handige benadering bieden voor het afhandelen van uitzonderingen. Het ErrorBoundary onderdeel
- Geeft de onderliggende inhoud weer wanneer er geen fout is opgetreden.
- Geeft de fout-UI weer wanneer een niet-verwerkte uitzondering wordt geregistreerd door een component binnen de foutgrens.
Als u een foutgrens wilt definiëren, gebruikt u het ErrorBoundary onderdeel om een of meer andere onderdelen te verpakken. De foutgrens beheert niet-verwerkte uitzonderingen die worden gegenereerd door de onderdelen die erin worden verpakt.
<ErrorBoundary>
...
</ErrorBoundary>
Als u een foutgrens op een globale manier wilt implementeren, voegt u de grens rond de hoofdinhoud van de hoofdindeling van de app toe.
In MainLayout.razor
:
<article class="content px-4">
<ErrorBoundary>
@Body
</ErrorBoundary>
</article>
In Blazor Web App, waarbij de foutgrens alleen wordt toegepast op een statisch MainLayout
-onderdeel, is de grens alleen actief tijdens statische server-side rendering (SSR). De grens wordt niet geactiveerd omdat een onderdeel verderop in de onderdeelhiërarchie interactief is.
Een interactieve weergavemodus kan niet worden toegepast op het MainLayout
onderdeel, omdat de parameter Body
van het onderdeel een RenderFragment gemachtigde is, die willekeurige code is en niet kan worden geserialiseerd. Als u interactiviteit breed wilt inschakelen voor het MainLayout
-onderdeel en de rest van de onderdelen verderop in de componenthiërarchie, moet de app een globale interactieve rendermodus gebruiken door de interactieve rendermodus toe te passen op de HeadOutlet
- en Routes
onderdeelexemplaren in het hoofdonderdeel van de app. Dit is meestal het App
onderdeel. In het volgende voorbeeld wordt de weergavemodus Interactive Server (InteractiveServer
) wereldwijd gebruikt.
In Components/App.razor
:
<HeadOutlet @rendermode="InteractiveServer" />
...
<Routes @rendermode="InteractiveServer" />
Als u globale interactiviteit liever niet inschakelt, plaatst u de foutgrens verderop in de componenthiërarchie. De belangrijkste concepten waarmee u rekening moet houden, zijn dat waar de foutgrens zich ook bevindt:
- Als het onderdeel waarin de foutgrens wordt geplaatst niet interactief is, kan de foutgrens alleen op de server worden geactiveerd tijdens statische SSR. De grens kan bijvoorbeeld worden geactiveerd wanneer een fout wordt opgeworpen in een component lifecycle-methode, maar niet voor een gebeurtenis die wordt veroorzaakt door gebruikersinteractie in de component, zoals een fout die wordt opgeworpen door een klikhandeling van een knop.
- Als het onderdeel waarin de foutgrens wordt geplaatst interactief is, kan de foutgrens worden geactiveerd voor interactieve onderdelen die erin worden verpakt.
Notitie
De voorgaande overwegingen zijn niet relevant voor zelfstandige Blazor WebAssembly apps, omdat de CSR (Client Side Rendering) van een Blazor WebAssembly-app volledig interactief is.
Bekijk het volgende voorbeeld, waarbij een uitzondering die door een ingesloten tellercomponent wordt gegenereerd, wordt opgevangen door een foutgrens in het Home
-component, dat een interactieve weergavemodus gebruikt.
EmbeddedCounter.razor
:
<h1>Embedded Counter</h1>
<p role="status">Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
if (currentCount > 5)
{
throw new InvalidOperationException("Current count is too big!");
}
}
}
Home.razor
:
@page "/"
@rendermode InteractiveServer
<PageTitle>Home</PageTitle>
<h1>Home</h1>
<ErrorBoundary>
<EmbeddedCounter />
</ErrorBoundary>
Bekijk het volgende voorbeeld, waarbij een uitzondering die wordt gegenereerd door een ingebouwde tellercomponent, wordt onderschept door een foutgrenscomponent in het Home
-onderdeel.
EmbeddedCounter.razor
:
<h1>Embedded Counter</h1>
<p role="status">Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
if (currentCount > 5)
{
throw new InvalidOperationException("Current count is too big!");
}
}
}
Home.razor
:
@page "/"
<PageTitle>Home</PageTitle>
<h1>Home</h1>
<ErrorBoundary>
<EmbeddedCounter />
</ErrorBoundary>
Als de niet-afgehandelde uitzondering wordt gegooid voor een currentCount
boven vijf:
- De fout wordt normaal geregistreerd (
System.InvalidOperationException: Current count is too big!
). - De uitzondering wordt verwerkt door de foutgrens.
- De standaardfoutgebruikersinterface wordt weergegeven door de foutgrens.
Het ErrorBoundary-onderdeel geeft een leeg <div>
element weer met behulp van de blazor-error-boundary
CSS-klasse voor de bijbehorende foutinhoud. De kleuren, tekst en het pictogram voor de standaardgebruikersinterface worden gedefinieerd in het opmaakmodel van de app in de wwwroot
map, zodat u de gebruikersinterface voor fouten kunt aanpassen.
De standaardfoutinhoud wijzigen:
- Verpakt de onderdelen van de foutgrens in de eigenschap ChildContent.
- Stel de eigenschap ErrorContent in op de foutinhoud.
In het volgende voorbeeld wordt het EmbeddedCounter
-onderdeel verpakt en wordt aangepaste foutinhoud geleverd:
<ErrorBoundary>
<ChildContent>
<EmbeddedCounter />
</ChildContent>
<ErrorContent>
<p class="errorUI">😈 A rotten gremlin got us. Sorry!</p>
</ErrorContent>
</ErrorBoundary>
In het voorgaande voorbeeld bevat het opmaakmodel van de app waarschijnlijk een errorUI
CSS-klasse om de inhoud te stylen. De foutinhoud wordt weergegeven vanuit de eigenschap ErrorContent zonder een element op blokniveau. Een element op blokniveau, zoals een sectie (<div>
) of een alinea (<p>
), kan de opmaak van foutinhoud omsluiten, maar dit is niet vereist.
Gebruik eventueel de context (@context
) van de ErrorContent om foutgegevens op te halen:
<ErrorContent>
@context.HelpLink
</ErrorContent>
De ErrorContent kan ook de context een naam geven. In het volgende voorbeeld krijgt de context de naam exception
:
<ErrorContent Context="exception">
@exception.HelpLink
</ErrorContent>
Waarschuwing
Vermijd altijd het blootstellen van foutinformatie aan clients op internet, wat een beveiligingsrisico is.
Als de foutgrens is gedefinieerd in de indeling van de app, wordt de foutgebruikersinterface weergegeven, ongeacht naar welke pagina de gebruiker navigeert nadat de fout is opgetreden. We raden u aan in de meeste scenario's een beperkt bereik van foutgrenzen te bepalen. Als u een foutgrens breed begrenst, kunt u deze opnieuw instellen op een niet-foutstatus op volgende paginanavigatiegebeurtenissen door de Recover methode van de foutgrens aan te roepen.
In MainLayout.razor
:
- Voeg een veld voor de ErrorBoundary toe aan een verwijzing vast te leggen met de
@ref
kenmerkrichtlijn. - In de
OnParameterSet
levenscyclusmethodekunt u een herstel activeren op de foutgrens met Recover om de fout te wissen wanneer de gebruiker naar een ander onderdeel navigeert.
...
<ErrorBoundary @ref="errorBoundary">
@Body
</ErrorBoundary>
...
@code {
private ErrorBoundary? errorBoundary;
protected override void OnParametersSet()
{
errorBoundary?.Recover();
}
}
Om de oneindige lus te vermijden waarin het herstellen van een fout leidt tot het opnieuw renderen van een component dat de fout opnieuw veroorzaakt, roep Recover niet aan vanuit de renderinglogica. Roep alleen Recover aan wanneer:
- De gebruiker voert een gebruikersinterfacebeweging uit, zoals het selecteren van een knop om aan te geven dat ze een procedure opnieuw willen proberen of wanneer de gebruiker naar een nieuw onderdeel navigeert.
- Aanvullende logica die wordt uitgevoerd, verwijdert ook de uitzondering. Wanneer het onderdeel opnieuw wordt uitgevoerd, treedt de fout niet opnieuw op.
In het volgende voorbeeld kan de gebruiker herstellen van de uitzondering met een knop:
<ErrorBoundary @ref="errorBoundary">
<ChildContent>
<EmbeddedCounter />
</ChildContent>
<ErrorContent>
<div class="alert alert-danger" role="alert">
<p class="fs-3 fw-bold">😈 A rotten gremlin got us. Sorry!</p>
<p>@context.HelpLink</p>
<button class="btn btn-info" @onclick="_ => errorBoundary?.Recover()">
Clear
</button>
</div>
</ErrorContent>
</ErrorBoundary>
@code {
private ErrorBoundary? errorBoundary;
}
U kunt ook ErrorBoundary subclassen voor aangepaste verwerking door OnErrorAsyncte overschrijven. In het volgende voorbeeld wordt alleen de fout vastgelegd, maar u kunt alle gewenste foutcodes implementeren. U kunt de regel verwijderen die een CompletedTask retourneert indien uw code wacht op een asynchrone taak.
CustomErrorBoundary.razor
:
@inherits ErrorBoundary
@inject ILogger<CustomErrorBoundary> Logger
@if (CurrentException is null)
{
@ChildContent
}
else if (ErrorContent is not null)
{
@ErrorContent(CurrentException)
}
@code {
protected override Task OnErrorAsync(Exception ex)
{
Logger.LogError(ex, "😈 A rotten gremlin got us. Sorry!");
return Task.CompletedTask;
}
}
Het voorgaande voorbeeld kan ook als klasse worden geïmplementeerd.
CustomErrorBoundary.cs
:
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
namespace BlazorSample;
public class CustomErrorBoundary : ErrorBoundary
{
[Inject]
ILogger<CustomErrorBoundary> Logger { get; set; } = default!;
protected override Task OnErrorAsync(Exception ex)
{
Logger.LogError(ex, "😈 A rotten gremlin got us. Sorry!");
return Task.CompletedTask;
}
}
Een van de voorgaande implementaties die in een onderdeel worden gebruikt:
<CustomErrorBoundary>
...
</CustomErrorBoundary>
Alternatieve algemene afhandeling van uitzonderingen
De benadering die in deze sectie wordt beschreven, is van toepassing op Blazor Server, Blazor WebAssemblyen Blazor Web Appdie een globale interactieve weergavemodus gebruiken (InteractiveServer
, InteractiveWebAssembly
of InteractiveAuto
). De benadering werkt niet met Blazor Web Appdie per-pagina/component rendermodi gebruiken of met statische server-side rendering (statische SSR), omdat de benadering afhankelijk is van een CascadingValue
/CascadingParameter
, wat niet werkt over de grenzen van de rendermodus of met componenten die statische SSR gebruiken.
Een alternatief voor het gebruik van foutgrenzen (ErrorBoundary) is om een aangepast foutcomponent als een CascadingValue
door te geven aan onderliggende componenten. Een voordeel van het gebruik van een onderdeel ten opzichte van een geïnjecteerde service of een aangepaste logger-implementatie is dat een trapsgewijs onderdeel inhoud kan weergeven en CSS-stijlen kan toepassen wanneer er een fout optreedt.
In het volgende ProcessError
voorbeeld van een onderdeel worden alleen fouten opgeslagen, maar methoden van het onderdeel kunnen fouten op elke manier verwerken die door de app zijn vereist, inclusief door het gebruik van meerdere foutverwerkingsmethoden.
ProcessError.razor
:
@inject ILogger<ProcessError> Logger
<CascadingValue Value="this">
@ChildContent
</CascadingValue>
@code {
[Parameter]
public RenderFragment? ChildContent { get; set; }
public void LogError(Exception ex)
{
Logger.LogError("ProcessError.LogError: {Type} Message: {Message}",
ex.GetType(), ex.Message);
// Call StateHasChanged if LogError directly participates in
// rendering. If LogError only logs or records the error,
// there's no need to call StateHasChanged.
//StateHasChanged();
}
}
Notitie
Zie ASP.NET Core Razor-onderdelenvoor meer informatie over RenderFragment.
Wanneer u deze methode in een Blazor Web Appgebruikt, opent u het Routes
onderdeel en verpakt u het Router onderdeel (<Router>...</Router>
) met het ProcessError
-onderdeel. Hierdoor kan het ProcessError
onderdeel trapsgewijs omlaag gaan naar een onderdeel van de app waarin het ProcessError
onderdeel wordt ontvangen als een CascadingParameter
.
In Routes.razor
:
<ProcessError>
<Router ...>
...
</Router>
</ProcessError>
Wanneer u deze methode gebruikt in een Blazor Server- of Blazor WebAssembly-app, opent u het App
onderdeel, verpakt u het Router onderdeel (<Router>...</Router>
) met het ProcessError
-onderdeel. Hierdoor kan het ProcessError
onderdeel trapsgewijs omlaag gaan naar een onderdeel van de app waarin het ProcessError
onderdeel wordt ontvangen als een CascadingParameter
.
In App.razor
:
<ProcessError>
<Router ...>
...
</Router>
</ProcessError>
Fouten in een onderdeel verwerken:
Wijs het
ProcessError
onderdeel aan als eenCascadingParameter
in het@code
blok. Voeg in een voorbeeldCounter
onderdeel in een app op basis van een Blazor projectsjabloon de volgendeProcessError
eigenschap toe:[CascadingParameter] public ProcessError? ProcessError { get; set; }
Roep een foutverwerkingsmethode aan in een
catch
blok met een geschikt uitzonderingstype. Het voorbeeldProcessError
onderdeel biedt slechts éénLogError
methode, maar het onderdeel voor foutverwerking kan een willekeurig aantal methoden voor foutverwerking bieden om te voldoen aan alternatieve vereisten voor foutverwerking in de app. Het volgendeCounter
onderdeel@code
blokvoorbeeld bevat deProcessError
cascaderende parameter en vangt een uitzondering op voor logboekregistratie wanneer het aantal groter is dan vijf.@code { private int currentCount = 0; [CascadingParameter] public ProcessError? ProcessError { get; set; } private void IncrementCount() { try { currentCount++; if (currentCount > 5) { throw new InvalidOperationException("Current count is over five!"); } } catch (Exception ex) { ProcessError?.LogError(ex); } } }
De vastgelegde fout:
fail: {COMPONENT NAMESPACE}.ProcessError[0]
ProcessError.LogError: System.InvalidOperationException Message: Current count is over five!
Als de methode LogError
rechtstreeks deelneemt aan rendering, zoals het weergeven van een aangepaste foutberichtbalk of het wijzigen van de CSS-stijlen van de weergegeven elementen, roept u StateHasChanged
aan het einde van de LogError
-methode aan om de gebruikersinterface opnieuw te genereren.
Omdat de benaderingen in deze sectie fouten verwerken met een try-catch
-instructie, wordt de SignalR verbinding tussen de client en server niet verbroken wanneer er een fout optreedt en het circuit actief blijft. Andere onverwerkte uitzonderingen blijven fataal voor een circuit. Zie de sectie over hoe een circuit reageert op niet-verwerkte uitzonderingenvoor meer informatie.
Een app kan een onderdeel voor foutverwerking gebruiken als een trapsgewijze waarde om fouten op een gecentraliseerde manier te verwerken.
Het volgende ProcessError
onderdeel geeft zichzelf door als een CascadingValue
aan kindcomponenten. Het volgende voorbeeld registreert alleen de fout, maar methoden van het onderdeel kunnen fouten op elke manier verwerken die vereist zijn voor de app, inclusief door het gebruik van meerdere foutverwerkingsmethoden. Een voordeel van het gebruik van een onderdeel ten opzichte van een geïnjecteerde service of een aangepaste logger-implementatie is dat een trapsgewijs onderdeel inhoud kan weergeven en CSS-stijlen kan toepassen wanneer er een fout optreedt.
ProcessError.razor
:
@using Microsoft.Extensions.Logging
@inject ILogger<ProcessError> Logger
<CascadingValue Value="this">
@ChildContent
</CascadingValue>
@code {
[Parameter]
public RenderFragment ChildContent { get; set; }
public void LogError(Exception ex)
{
Logger.LogError("ProcessError.LogError: {Type} Message: {Message}",
ex.GetType(), ex.Message);
}
}
Notitie
Zie ASP.NET Core Razor-onderdelenvoor meer informatie over RenderFragment.
In het App
-onderdeel verpakt u het Router onderdeel met het ProcessError
-onderdeel. Hierdoor kan het ProcessError
onderdeel trapsgewijs omlaag gaan naar een onderdeel van de app waarin het ProcessError
onderdeel wordt ontvangen als een CascadingParameter
.
App.razor
:
<ProcessError>
<Router ...>
...
</Router>
</ProcessError>
Fouten in een onderdeel verwerken:
Geef het
ProcessError
onderdeel aan als eenCascadingParameter
in het@code
blok:[CascadingParameter] public ProcessError ProcessError { get; set; }
Roep een foutverwerkingsmethode aan in een
catch
blok met een geschikt uitzonderingstype. Het voorbeeldProcessError
onderdeel biedt slechts éénLogError
methode, maar het onderdeel voor foutverwerking kan een willekeurig aantal methoden voor foutverwerking bieden om te voldoen aan alternatieve vereisten voor foutverwerking in de app.try { ... } catch (Exception ex) { ProcessError.LogError(ex); }
Met behulp van het voorgaande voorbeeld ProcessError
component en LogError
methode geeft de console voor ontwikkelaarshulpprogramma's van de browser de vastgelopen, vastgelegde fout aan:
fail: {COMPONENT NAMESPACE}.Shared.ProcessError[0]
ProcessError.LogError: System.NullReferenceException Message: Object reference not set to an instance of an object.
Als de methode LogError
rechtstreeks deelneemt aan rendering, zoals het weergeven van een aangepaste foutberichtbalk of het wijzigen van de CSS-stijlen van de weergegeven elementen, roept u StateHasChanged
aan het einde van de LogError
-methode aan om de gebruikersinterface opnieuw te genereren.
Omdat de benaderingen in deze sectie fouten verwerken met een try-catch
-instructie, wordt de SignalR-verbinding van een Blazor app tussen de client en de server niet verbroken wanneer er een fout optreedt en het circuit actief blijft. Een onverwerkte uitzondering is fataal voor een circuit. Zie de sectie over hoe een circuit reageert op niet-verwerkte uitzonderingenvoor meer informatie.
Logboekfouten met een permanente provider
Als er een niet-verwerkte uitzondering optreedt, wordt de uitzondering geregistreerd bij ILogger exemplaren die zijn geconfigureerd in de servicecontainer. Blazor apps legen console-uitvoer vast met de Console Logging Provider. Overweeg om te loggen naar een locatie op de server (of back-endweb-API voor client-side apps) met een provider die de logboekgrootte en logboekrotatie beheert. De app kan ook gebruikmaken van een APM-service (Application Performance Management), zoals Azure Application Insights (Azure Monitor).
Notitie
Systeemeigen Application Insights-functies ter ondersteuning van apps aan de clientzijde en systeemeigen Blazor frameworkondersteuning voor Google Analytics- kunnen beschikbaar komen in toekomstige releases van deze technologieën. Zie Support App Insights in Blazor WASM Client Side (microsoft/ApplicationInsights-dotnet #2143) en Web Analytics and Diagnostics (inclusief koppelingen naar community-implementaties) (dotnet/aspnetcore #5461)voor meer informatie. Ondertussen kan een app aan de clientzijde de Application Insights JavaScript SDK- gebruiken met JS interop- om fouten rechtstreeks vanuit een app aan de clientzijde te registreren bij Application Insights.
Tijdens de ontwikkeling in een Blazor-app die via een circuit wordt uitgevoerd, verzendt de app meestal de volledige details van uitzonderingen naar de console van de browser om te helpen bij het opsporen van fouten. In productie worden gedetailleerde fouten niet naar clients verzonden, maar de volledige details van een uitzondering worden vastgelegd op de server.
U moet bepalen welke incidenten moeten worden geregistreerd en het ernstniveau van geregistreerde incidenten. Vijandige gebruikers kunnen mogelijk opzettelijk fouten veroorzaken. Meld bijvoorbeeld geen incident aan bij een fout waarbij een onbekende ProductId
wordt opgegeven in de URL van een onderdeel waarin productdetails worden weergegeven. Niet alle fouten moeten worden behandeld als incidenten voor logboekregistratie.
Zie de volgende artikelen voor meer informatie:
- ASP.NET Core Blazor logboekregistratie
- fouten afhandelen in ASP.NET Core‡
- Web-API's maken met ASP.NET Core-
‡Van toepassing op Blazor-apps aan de serverzijde en andere ASP.NET Core-apps die back-end-apps voor web-API zijn voor Blazor. Apps aan de clientzijde kunnen foutinformatie op de client onderscheppen en verzenden naar een web-API, die de foutgegevens registreert bij een permanente logboekregistratieprovider.
Als er een niet-verwerkte uitzondering optreedt, wordt de uitzondering geregistreerd bij ILogger exemplaren die zijn geconfigureerd in de servicecontainer. Blazor apps loggen console-uitvoer met de Console Logging Provider. Overweeg om te loggen naar een permanentere locatie op de server door foutinformatie te verzenden naar een backend web-API die een logboekprovider gebruikt met loggroottebeheer en logrotatie. De back-end-web-API-app kan ook een APM-service (Application Performance Management), zoals Azure Application Insights (Azure Monitor)-†, gebruiken om foutgegevens vast te leggen die worden ontvangen van clients.
U moet bepalen welke incidenten moeten worden geregistreerd en het ernstniveau van geregistreerde incidenten. Vijandige gebruikers kunnen mogelijk opzettelijk fouten uitlokken. Meld bijvoorbeeld geen incident aan bij een fout waarbij een onbekende ProductId
wordt opgegeven in de URL van een onderdeel waarin productdetails worden weergegeven. Niet alle fouten moeten worden behandeld als incidenten voor logboekregistratie.
Zie de volgende artikelen voor meer informatie:
- ASP.NET Core Blazor logboekregistratie
- fouten afhandelen in ASP.NET Core‡
- Web-API's maken met ASP.NET Core-
†Native Application Insights-functies ter ondersteuning van apps aan de clientzijde en systeemeigen Blazor frameworkondersteuning voor Google Analytics- kunnen beschikbaar komen in toekomstige releases van deze technologieën. Zie Support App Insights in Blazor WASM Client Side (microsoft/ApplicationInsights-dotnet #2143) en Web Analytics and Diagnostics (inclusief koppelingen naar community-implementaties) (dotnet/aspnetcore #5461)voor meer informatie. Ondertussen kan een app aan de clientzijde de Application Insights JavaScript SDK- gebruiken met JS interop- om fouten rechtstreeks vanuit een app aan de clientzijde te registreren bij Application Insights.
‡Van toepassing op ASP.NET Core-apps aan de serverzijde die back-end-apps voor web-API's zijn voor Blazor-apps. Apps aan de clientzijde trapen en verzenden foutinformatie naar een web-API, waarmee de foutgegevens worden aangemeld bij een permanente logboekregistratieprovider.
Plaatsen waar fouten kunnen optreden
Framework en app-code kunnen niet-verwerkte uitzonderingen activeren op een van de volgende locaties, die verder worden beschreven in de volgende secties van dit artikel:
Instantiëring van onderdelen
Wanneer Blazor een exemplaar van een onderdeel maakt:
- De constructor van het onderdeel wordt aangeroepen.
- De constructors van DI-services die aan de constructor van het onderdeel worden geleverd via de
@inject
-instructie of het kenmerk[Inject]
worden aangeroepen.
Een fout in een uitgevoerde constructor of een setter voor een [Inject]
eigenschap resulteert in een niet-verwerkte uitzondering en zorgt ervoor dat het framework het onderdeel niet kan instantiëren. Als de app via een circuit werkt, mislukt het circuit. Als constructorlogica uitzonderingen kan genereren, moet de app de uitzonderingen onderscheppen met behulp van een try-catch
-instructie met foutafhandeling en logboekregistratie.
Levenscyclusmethoden
Tijdens de levensduur van een onderdeel roept Blazorlevenscyclusmethodenaan. Als een levenscyclusmethode een uitzondering genereert, synchroon of asynchroon, is de uitzondering fataal voor een circuit. Voeg foutafhandelingslogica toe zodat componenten fouten in levenscyclusmethoden kunnen verwerken.
In het volgende voorbeeld waarin OnParametersSetAsync een methode aanroept om een product te verkrijgen:
- Een uitzondering die is opgetreden in de
ProductRepository.GetProductByIdAsync
-methode, wordt afgehandeld door eentry-catch
-instructie. - Wanneer het
catch
blok wordt uitgevoerd:-
loadFailed
is ingesteld optrue
, die wordt gebruikt om een foutbericht weer te geven aan de gebruiker. - De fout wordt geregistreerd.
-
@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?}"
@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);
}
}
Renderinglogica
De declaratieve markering in een Razor onderdeelbestand (.razor
) wordt gecompileerd in een C#-methode met de naam BuildRenderTree. Wanneer een onderdeel wordt weergegeven, BuildRenderTree een gegevensstructuur uitvoert en bouwt die de elementen, tekst en onderliggende onderdelen van het gerenderde onderdeel beschrijft.
Renderinglogica kan een uitzondering genereren. Een voorbeeld van dit scenario treedt op wanneer @someObject.PropertyName
wordt geëvalueerd, maar @someObject
is null
. Voor Blazor apps die via een circuit werken, is een door de renderlogica opgeworpen onverwerkte uitzondering fataal voor het circuit van de app.
Als u een NullReferenceException in de renderinglogica wilt voorkomen, moet u controleren op een null
-object voordat u de leden benadert. In het volgende voorbeeld worden person.Address
eigenschappen niet geopend als person.Address
is null
:
@if (person.Address != null)
{
<div>@person.Address.Line1</div>
<div>@person.Address.Line2</div>
<div>@person.Address.City</div>
<div>@person.Address.Country</div>
}
In de voorgaande code wordt ervan uitgegaan dat person
niet is null
. Vaak garandeert de structuur van de code dat een object bestaat op het moment dat het onderdeel wordt weergegeven. In dergelijke gevallen is het niet nodig om te controleren op null
in de renderlogica. In het vorige voorbeeld kan person
gegarandeerd bestaan omdat person
wordt gemaakt wanneer het onderdeel wordt geïnstantieerd, zoals in het volgende voorbeeld wordt weergegeven:
@code {
private Person person = new();
...
}
Gebeurtenishandlers
Code aan de clientzijde activeert aanroepen van C#-code wanneer gebeurtenis-handlers worden gemaakt met behulp van:
@onclick
@onchange
- Andere
@on...
kenmerken @bind
Gebeurtenishandlercode kan in deze scenario's een onverwerkte uitzondering genereren.
Als de app code aanroept die om externe redenen kan mislukken, vang uitzonderingen op door een try-catch
-instructie met foutafhandeling en loggen.
Als een eventhandler een onbehandelde uitzondering genereert (bijvoorbeeld wanneer een databasequery mislukt) die niet door de code van de ontwikkelaar is opgevangen en behandeld:
- Het framework registreert de uitzondering.
- In een Blazor app die via een circuit werkt, is de uitzondering dodelijk voor het circuit van de app.
Verwijdering van onderdelen
Een onderdeel kan bijvoorbeeld worden verwijderd uit de gebruikersinterface, omdat de gebruiker naar een andere pagina is genavigeerd. Wanneer een onderdeel dat System.IDisposable implementeert, wordt verwijderd uit de gebruikersinterface, roept het framework de Dispose methode van het onderdeel aan.
Als de Dispose
methode van het onderdeel een niet-verwerkte uitzondering genereert in een Blazor-app die via een circuit werkt, is de uitzondering onherstellijk voor het circuit van de app.
Als verwijderingslogica uitzonderingen kan genereren, moet de app de uitzonderingen onderscheppen met behulp van een try-catch
-instructie met foutafhandeling en logboekregistratie.
Zie ASP.NET Core Razor componentverwijderingvoor meer informatie over de verwijdering van onderdelen.
JavaScript-interoperabiliteit
IJSRuntime wordt geregistreerd door het Blazor framework. IJSRuntime.InvokeAsync staat .NET-code toe om asynchrone aanroepen uit te voeren naar de JavaScript-runtime (JS) in de browser van de gebruiker.
De volgende voorwaarden zijn van toepassing op foutafhandeling met InvokeAsync:
- Als een aanroep naar InvokeAsync synchroon mislukt, treedt er een .NET-uitzondering op. Een aanroep naar InvokeAsync kan bijvoorbeeld mislukken omdat de opgegeven argumenten niet kunnen worden geserialiseerd. Ontwikkelaarscode moet de uitzondering ondervangen. Als app-code in een gebeurtenis-handler of levenscyclusmethode voor onderdelen geen uitzondering verwerkt in een Blazor-app die via een circuit werkt, is de resulterende uitzondering onherstellijk voor het circuit van de app.
- Als een aanroep naar InvokeAsync asynchroon mislukt, mislukt de .NET-Task. Een oproep naar InvokeAsync kan bijvoorbeeld mislukken omdat de code aan de JS-zijde een uitzondering genereert of een
Promise
retourneert die is afgerond alsrejected
. Ontwikkelaarscode moet de uitzondering ondervangen. Als u de operatorawait
gebruikt, kunt u de methode-aanroep verpakken in eentry-catch
-instructie met foutafhandeling en logboekregistratie. Anders in een Blazor app die via een circuit werkt, resulteert de mislukte code in een onverwerkte uitzondering die dodelijk is voor het circuit van de app. - Oproepen naar InvokeAsync moeten binnen een bepaalde periode worden voltooid, anders treedt er een time-out op voor de oproep. De standaardtime-outperiode is één minuut. De time-out beschermt de code tegen verlies van netwerkconnectiviteit of JS code die nooit een voltooiingsbericht terugstuurt. Als er een time-out optreedt voor de oproep, mislukt de resulterende System.Threading.Tasks met een OperationCanceledException. Vang op en verwerk de uitzondering met logboekregistratie.
Op dezelfde manier kan JS code aanroepen naar .NET-methoden initiëren die worden aangegeven door het [JSInvokable]
kenmerk. Als deze .NET-methoden een onverwerkte uitzondering genereren:
- In een Blazor-app die via een circuit werkt, wordt de uitzondering niet als fataal behandeld voor het circuit van de app.
- De JS-side
Promise
wordt geweigerd.
U hebt de mogelijkheid om foutafhandelingscode te gebruiken aan de .NET-zijde of aan de JS-zijde van de methodeaanroep.
Zie de volgende artikelen voor meer informatie:
- JavaScript-functies aanroepen vanuit .NET-methoden in ASP.NET Core Blazor
- .NET-methoden aanroepen vanuit JavaScript-functies in ASP.NET Core Blazor
Vooraf renderen
Razor onderdelen standaard worden vooraf gegenereerd, zodat de weergegeven HTML-opmaak wordt geretourneerd als onderdeel van de eerste HTTP-aanvraag van de gebruiker.
In een Blazor-app die via een circuit opereert, functioneert prerendering door:
- Een nieuw circuit maken voor alle vooraf samengestelde onderdelen die deel uitmaken van dezelfde pagina.
- De initiële HTML genereren.
- Het circuit behandelen als
disconnected
totdat de browser van de gebruiker een SignalR verbinding met dezelfde server tot stand brengt. Wanneer de verbinding tot stand is gebracht, wordt de interactiviteit op het circuit hervat en wordt de HTML-markering van de onderdelen bijgewerkt.
Voor voor-gerenderde client-side componenten werkt prerendering door:
- Het genereren van initiële HTML op de server voor alle vooraf gegenereerde onderdelen die deel uitmaken van dezelfde pagina.
- Het onderdeel interactief maken op de client nadat de browser de gecompileerde code van de app en de .NET-runtime (indien niet al geladen) op de achtergrond heeft geladen.
Als een component een niet-verwerkte uitzondering veroorzaakt tijdens het vooraf renderen, bijvoorbeeld tijdens een levenscyclusmethode of in de weergavelogica:
- In een Blazor-app die via een circuit werkt, is de uitzondering dodelijk voor het circuit. Voor vooraf gegenereerde onderdelen aan de clientzijde voorkomt de uitzondering dat het onderdeel wordt weergegeven.
- De uitzondering wordt omhoog over de aanroepstack van de ComponentTagHelpergestuurd.
Onder normale omstandigheden, wanneer prerenderen mislukt, is het niet logisch om het component te blijven bouwen en weer te geven, omdat een werkend component niet kan worden weergegeven.
Als u fouten wilt tolereren die kunnen optreden tijdens het prerendering, moet foutafhandelingslogica worden geplaatst in een onderdeel dat uitzonderingen kan genereren. Gebruik try-catch
-instructies met foutafhandeling en logging. In plaats van de ComponentTagHelper in een try-catch
-instructie te plaatsen, moet u foutafhandelingslogica plaatsen in het onderdeel dat door de ComponentTagHelperwordt weergegeven.
Geavanceerde scenario's
Recursieve rendering
Onderdelen kunnen recursief worden genest. Dit is handig voor het weergeven van recursieve gegevensstructuren. Een TreeNode
-component kan bijvoorbeeld meerdere TreeNode
-componenten renderen voor elk van de onderliggende knooppunten.
Wanneer u recursief rendert, vermijdt u coderingspatronen die resulteren in oneindige recursie:
- Geef niet recursief een gegevensstructuur weer die een cyclus bevat. Geef bijvoorbeeld geen boomknooppunt weer waarvan de kinderen zichzelf omvatten.
- Maak geen keten van indelingen die een cyclus bevatten. Maak bijvoorbeeld geen indeling waarvan de indeling zichzelf is.
- Laat een eindgebruiker recursie-invarianten (regels) niet schenden via schadelijke gegevensinvoer of JavaScript-interopaanroepen.
Oneindige lussen tijdens rendering:
- Zorgt ervoor dat het renderingproces voor altijd wordt voortgezet.
- Komt overeen met het maken van een niet-terminerende lus.
In deze scenario's mislukt de Blazor en probeert meestal het volgende te doen:
- Verbruik zoveel CPU-tijd als is toegestaan door het besturingssysteem, voor onbepaalde tijd.
- Verbruik een onbeperkte hoeveelheid geheugen. Het gebruik van onbeperkt geheugen is gelijk aan het scenario waarbij een niet-onbepaalde lus vermeldingen toevoegt aan een verzameling bij elke iteratie.
Om oneindige recursiepatronen te voorkomen, moet u ervoor zorgen dat recursieve renderingcode geschikte stopomstandigheden bevat.
Aangepaste weergavestructuurlogica
De meeste Razor onderdelen worden geïmplementeerd als Razor onderdeelbestanden (.razor
) en worden gecompileerd door het framework om logica te produceren die op een RenderTreeBuilder werkt om hun uitvoer weer te geven. Een ontwikkelaar kan echter handmatig RenderTreeBuilder logica implementeren met behulp van procedurele C#-code. Zie ASP.NET Core Blazor geavanceerde scenario's (render tree construction)voor meer informatie.
Waarschuwing
Het gebruik van logica van handmatige renderboomconstructie wordt beschouwd als een geavanceerd en onveilig scenario, niet aanbevolen voor algemene componentontwikkeling.
Als RenderTreeBuilder code is geschreven, moet de ontwikkelaar de juistheid van de code garanderen. De ontwikkelaar moet er bijvoorbeeld voor zorgen dat:
- Oproepen naar OpenElement en CloseElement zijn correct uitgebalanceerd.
- Kenmerken worden alleen toegevoegd op de juiste plaatsen.
Onjuiste logica in de opbouwfunctie voor handmatige renderstructuur kan willekeurig onvoorspelbaar gedrag veroorzaken, waaronder crashes, waardoor de app of server stopt met reageren, en beveiligingsproblemen.
Overweeg handmatige logica voor de renderboomopbouwer op hetzelfde complexiteitsniveau en met hetzelfde niveau van gevaar als het handmatig schrijven van assemblycode of Microsoft Intermediate Language (MSIL)-instructies.
Aanvullende informatiebronnen
†Geldt voor back-end ASP.NET Core web-API-apps die door Blazor-apps aan de clientzijde worden gebruikt voor logregistratie.