Zpracování chyb v aplikacích ASP.NET Core Blazor
Poznámka:
Toto není nejnovější verze tohoto článku. Aktuální verzi najdete v tomto článku ve verzi .NET 9.
Upozorňující
Tato verze ASP.NET Core se už nepodporuje. Další informace najdete v zásadách podpory .NET a .NET Core. Aktuální verzi najdete v tomto článku ve verzi .NET 9.
Důležité
Tyto informace se týkají předběžného vydání produktu, který může být podstatně změněn před komerčním vydáním. Microsoft neposkytuje žádné záruky, výslovné ani předpokládané, týkající se zde uváděných informací.
Aktuální verzi najdete v tomto článku ve verzi .NET 9.
Tento článek popisuje, jak spravovat neošetřené výjimky a jak Blazor vyvíjet aplikace, které detekují a zpracovávají chyby.
Podrobné chyby během vývoje
Blazor Pokud aplikace během vývoje nefunguje správně, pomůže vám při řešení potíží a opravě problému získat podrobné informace o chybách. Když dojde k chybě, Blazor aplikace zobrazí světle žlutý pruh v dolní části obrazovky:
- Během vývoje vás panel přesměruje na konzolu prohlížeče, kde se zobrazí výjimka.
- V produkčním prostředí panel upozorní uživatele, že došlo k chybě, a doporučí aktualizaci prohlížeče.
Uživatelské rozhraní pro toto zpracování chyb je součástí Blazor šablon projektů. Ne všechny verze Blazor šablon projektů používají data-nosnippet
atribut k signálu prohlížečům, aby neukázely obsah uživatelského rozhraní chyby, ale všechny verze Blazor dokumentace tento atribut používají.
V prostředí Blazor Web App, přizpůsobit prostředí v komponentě MainLayout
. Protože pomocné rutiny značek prostředí (například<environment include="Production">...</environment>
) nejsou v Razor komponentách podporované, následující příklad vloží IHostEnvironment do konfigurace chybových zpráv pro různá prostředí.
V horní části :MainLayout.razor
@inject IHostEnvironment HostEnvironment
Vytvořte nebo upravte Blazor kód uživatelského rozhraní chyby:
<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>
Blazor Server V aplikaci upravte prostředí v Pages/_Host.cshtml
souboru. Následující příklad používá pomocníka značky prostředí ke konfiguraci chybových zpráv pro různá prostředí.
Blazor Server V aplikaci upravte prostředí v Pages/_Layout.cshtml
souboru. Následující příklad používá pomocníka značky prostředí ke konfiguraci chybových zpráv pro různá prostředí.
Blazor Server V aplikaci upravte prostředí v Pages/_Host.cshtml
souboru. Následující příklad používá pomocníka značky prostředí ke konfiguraci chybových zpráv pro různá prostředí.
Vytvořte nebo upravte Blazor kód uživatelského rozhraní chyby:
<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>
Blazor WebAssembly V aplikaci přizpůsobte prostředí v wwwroot/index.html
souboru:
<div id="blazor-error-ui" data-nosnippet>
An unhandled error has occurred.
<a href="" class="reload">Reload</a>
<a class="dismiss">🗙</a>
</div>
Element blazor-error-ui
je obvykle skrytý z důvodu přítomnosti display: none
stylu blazor-error-ui
třídy CSS v automaticky generované šabloně stylů aplikace. Pokud dojde k chybě, architektura se vztahuje display: block
na prvek.
Element blazor-error-ui
je obvykle skrytý kvůli přítomnosti display: none
stylu blazor-error-ui
třídy CSS v šabloně stylů webu ve wwwroot/css
složce. Pokud dojde k chybě, architektura se vztahuje display: block
na prvek.
Podrobné chyby okruhu
Tato část se vztahuje na Blazor Web Appprovoz přes okruh.
Tato část se týká Blazor Server aplikací.
Chyby na straně klienta nezahrnují zásobník volání a neposkytují podrobnosti o příčině chyby, ale protokoly serveru tyto informace obsahují. Pro účely vývoje mohou být informace o chybách citlivého okruhu zpřístupněny klientovi povolením podrobných chyb.
Nastavte CircuitOptions.DetailedErrors na hodnotu true
. Další informace a příklad najdete v ASP.NET BlazorSignalR základních doprovodných materiálech.
Alternativou k nastavení CircuitOptions.DetailedErrors je nastavení konfiguračního DetailedErrors
klíče v true
souboru nastavení prostředí aplikace Development
(appsettings.Development.json
). Kromě toho nastavte SignalR protokolování na straně serveru (Microsoft.AspNetCore.SignalR
) na ladění nebo trasování pro podrobné SignalR protokolování.
appsettings.Development.json
:
{
"DetailedErrors": true,
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information",
"Microsoft.AspNetCore.SignalR": "Debug"
}
}
}
Konfigurační DetailedErrors klíč lze také nastavit tak, aby true
používal ASPNETCORE_DETAILEDERRORS
proměnnou prostředí s hodnotou true
na Development
/Staging
serverech prostředí nebo v místním systému.
Upozorňující
Vždy se vyhněte zveřejnění informací o chybách klientům na internetu, což je bezpečnostní riziko.
Podrobné chyby pro Razor vykreslování na straně serveru komponent
Tato část se týká Blazor Web Apps.
RazorComponentsServiceOptions.DetailedErrors Pomocí možnosti můžete řídit vytváření podrobných informací o chybách při Razor vykreslování na straně serveru. Výchozí hodnota je false
.
Následující příklad umožňuje podrobné chyby:
builder.Services.AddRazorComponents(options =>
options.DetailedErrors = builder.Environment.IsDevelopment());
Upozorňující
Povolte v prostředí jenom podrobné chyby Development
. Podrobné chyby můžou obsahovat citlivé informace o aplikaci, kterou můžou uživatelé se zlými úmysly použít při útoku.
Předchozí příklad poskytuje stupeň bezpečnosti nastavením hodnoty DetailedErrors na základě hodnoty vrácené IsDevelopment. Když je aplikace v Development
prostředí, DetailedErrors je nastavená na true
hodnotu . Tento přístup není hloupý, protože je možné hostovat produkční aplikaci na veřejném serveru v Development
prostředí.
Správa neošetřených výjimek v kódu vývojáře
Aby aplikace pokračovala po chybě, musí mít aplikace logiku zpracování chyb. Další části tohoto článku popisují potenciální zdroje neošetřených výjimek.
V produkčním prostředí nevykreslujte zprávy o výjimce architektury ani trasování zásobníku v uživatelském rozhraní. Vykreslování zpráv výjimek nebo trasování zásobníku může:
- Zveřejnit citlivé informace koncovým uživatelům.
- Pomozte uživateli se zlými úmysly zjistit slabá místa v aplikaci, která může ohrozit zabezpečení aplikace, serveru nebo sítě.
Neošetřené výjimky pro okruhy
Tato část se týká aplikací na straně serveru, které fungují přes okruh.
Razor komponenty s povolenou interaktivitou serveru jsou na serveru stavové. Zatímco uživatelé pracují s komponentou na serveru, udržují připojení k serveru známému jako okruh. Okruh obsahuje aktivní instance komponent a mnoho dalších aspektů stavu, například:
- Nejnovější vykreslený výstup komponent.
- Aktuální sada delegátů zpracování událostí, které by mohly být aktivovány událostmi na straně klienta.
Pokud uživatel aplikaci otevře na několika kartách prohlížeče, uživatel vytvoří více nezávislých okruhů.
Blazor považuje většinu neošetřených výjimek za závažnou pro okruh, ve kterém k nim dochází. Pokud se okruh ukončí kvůli neošetřené výjimce, uživatel může s aplikací dál pracovat, a to tak, že stránku znovu načte a vytvoří nový okruh. Okruhy mimo okruhy ukončené, což jsou okruhy pro jiné uživatele nebo jiné karty prohlížeče, to neovlivní. Tento scénář je podobný desktopové aplikaci, která se chybově ukončí. Aplikace s chybovým ukončením se musí restartovat, ale jiné aplikace to neovlivní.
Architektura ukončí okruh, pokud dojde k neošetřené výjimce z následujících důvodů:
- Neošetřená výjimka často opouští okruh v nedefinovaném stavu.
- Normální provoz aplikace není možné zaručit po neošetřené výjimce.
- Pokud okruh pokračuje v nedefinovaném stavu, můžou se v aplikaci objevit ohrožení zabezpečení.
Globální zpracování výjimek
Přístupy k globálnímu zpracování výjimek najdete v následujících částech:
- Hranice chyb: Platí pro všechny Blazor aplikace.
- Alternativní globální zpracování výjimek: Platí pro Blazor Server, Blazor WebAssemblya Blazor Web Apps (8.0 nebo novější), které přijímají globální interaktivní režim vykreslování.
Hranice chyb
Hranice chyb poskytují pohodlný přístup pro zpracování výjimek. Komponenta ErrorBoundary :
- Vykreslí podřízený obsah v případě, že nedošlo k chybě.
- Vykreslí uživatelské rozhraní chyby, pokud je neošetřená výjimka vyvolán libovolnou komponentou v rámci hranice chyby.
Chcete-li definovat hranici chyby, použijte komponentu ErrorBoundary k zabalení jedné nebo více dalších komponent. Hranice chyby spravuje neošetřené výjimky vyvolané komponentami, které zabalí.
<ErrorBoundary>
...
</ErrorBoundary>
Pokud chcete implementovat hranici chyb v globálním měřítku, přidejte hranici kolem základního obsahu hlavního rozložení aplikace.
V MainLayout.razor
:
<article class="content px-4">
<ErrorBoundary>
@Body
</ErrorBoundary>
</article>
V Blazor Web Apps chybovou hranicí použitou pouze pro statickou MainLayout
komponentu je hranice aktivní pouze při vykreslování na straně statického serveru (static SSR). Hranice se neaktivuje, protože komponenta dále v hierarchii komponent je interaktivní.
Interaktivní režim vykreslení nelze u MainLayout
komponenty použít, protože parametr komponenty Body
je RenderFragment delegát, což je libovolný kód a nedá se serializovat. Aby byla interaktivita pro komponentu MainLayout
a rest komponenty dále mimo hierarchii součástí, musí aplikace přijmout globální interaktivní režim vykreslování tím, že použije interaktivní režim vykreslování na HeadOutlet
instance a Routes
instance komponent v kořenové komponentě aplikace, což je obvykle komponenta App
. Následující příklad přijímá globálně režim vykreslování Interactive Server (InteractiveServer
).
V Components/App.razor
:
<HeadOutlet @rendermode="InteractiveServer" />
...
<Routes @rendermode="InteractiveServer" />
Pokud nechcete povolit globální interaktivitu, umístěte hranici chyby dále dolů v hierarchii komponent. Důležité koncepty, které je potřeba mít na paměti, jsou, že všude, kde je umístěna hranice chyby:
- Pokud komponenta, kde je umístěna hranice chyby, není interaktivní, je hranice chyby schopna aktivovat pouze na serveru během statického SSR. Hranice se například může aktivovat, když dojde k chybě v metodě životního cyklu komponenty, ale ne pro událost aktivovanou interaktivitou uživatele v rámci komponenty, například chybu vyvolanou obslužnou rutinou kliknutí na tlačítko.
- Pokud je komponenta, ve které je umístěna hranice chyby, interaktivní, je hranice chyby schopna aktivovat interaktivní komponenty, které zabalí.
Poznámka:
Předchozí aspekty nejsou relevantní pro samostatné Blazor WebAssembly aplikace, protože vykreslování aplikace na straně klienta (CSR) Blazor WebAssembly je zcela interaktivní.
Podívejte se na následující příklad, kdy výjimka vyvolaná vloženou komponentou čítače je zachycena hranici chyby v Home
komponentě, která přijímá interaktivní režim vykreslování.
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>
Podívejte se na následující příklad, kde výjimka vyvolaná vloženou komponentou čítače je zachycena hranici chyby v komponentě Home
.
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>
Pokud je neošetřená výjimka vyvolán pro currentCount
více než pět:
- Chyba se protokoluje normálně (
System.InvalidOperationException: Current count is too big!
). - Výjimku zpracovává hranice chyby.
- Výchozí uživatelské rozhraní chyby se vykreslí podle hranice chyby.
Komponenta ErrorBoundary vykresluje prázdný <div>
prvek pomocí blazor-error-boundary
třídy CSS pro jeho chybový obsah. Barvy, text a ikona výchozího uživatelského rozhraní jsou definované v šabloně stylů aplikace ve wwwroot
složce, takže můžete uživatelské rozhraní chyby přizpůsobit.
Změna výchozího obsahu chyby:
- Zabalte součásti hranice chyby ve ChildContent vlastnosti.
- ErrorContent Nastavte vlastnost na obsah chyby.
Následující příklad zabalí komponentu EmbeddedCounter
a dodává vlastní obsah chyb:
<ErrorBoundary>
<ChildContent>
<EmbeddedCounter />
</ChildContent>
<ErrorContent>
<p class="errorUI">😈 A rotten gremlin got us. Sorry!</p>
</ErrorContent>
</ErrorBoundary>
V předchozím příkladu pravděpodobně šablona stylů aplikace obsahuje errorUI
třídu CSS pro styl obsahu. Obsah chyby se vykreslí z ErrorContent vlastnosti bez elementu na úrovni bloku. Prvek na úrovni bloku, například dělení (<div>
) nebo prvek odstavce () může<p>
zabalit kód obsahu chyby, ale není povinný.
Volitelně můžete k získání chybových ErrorContent dat použít kontext (@context
):
<ErrorContent>
@context.HelpLink
</ErrorContent>
Kontext ErrorContent může také pojmenovat. V následujícím příkladu je kontext pojmenován exception
:
<ErrorContent Context="exception">
@exception.HelpLink
</ErrorContent>
Upozorňující
Vždy se vyhněte zveřejnění informací o chybách klientům na internetu, což je bezpečnostní riziko.
Pokud je hranice chyby definovaná v rozložení aplikace, uživatelské rozhraní chyby se zobrazí bez ohledu na to, na kterou stránku uživatel přejde po chybě. Ve většině scénářů doporučujeme zúžit hranice chyb. Pokud v širokém rozsahu rozsahu hranice chyby, můžete ho resetovat do stavu, který není chybový u následných událostí navigace na stránce volání metody hranice Recover chyby.
V MainLayout.razor
:
- Přidejte pole pro ErrorBoundary zachycení odkazu na něj pomocí direktivy atributu
@ref
. OnParameterSet
V metodě životního cyklu můžete aktivovat obnovení na hranici chyby a Recover vymazat chybu, když uživatel přejde na jinou komponentu.
...
<ErrorBoundary @ref="errorBoundary">
@Body
</ErrorBoundary>
...
@code {
private ErrorBoundary? errorBoundary;
protected override void OnParametersSet()
{
errorBoundary?.Recover();
}
}
Abyste se vyhnuli nekonečné smyčce, kdy obnovení pouze rerenderuje komponentu, která chybu znovu vyvolá, nezavolejte Recover z logiky vykreslování. Zavolat Recover pouze v případech:
- Uživatel provede gesto uživatelského rozhraní, například výběrem tlačítka, které označuje, že chce zopakovat proceduru nebo když uživatel přejde na novou komponentu.
- Další logika, která provede, také vymaže výjimku. Pokud je komponenta znovu vysunutá, chyba se znovu nezobrazí.
Následující příklad uživateli umožňuje obnovit výjimku pomocí tlačítka:
<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;
}
Můžete také podtřídu ErrorBoundary pro vlastní zpracování přepsáním OnErrorAsync. Následující příklad pouze zaprokoluje chybu, ale můžete implementovat libovolný kód pro zpracování chyb. Řádek, který vrací CompletedTask , můžete odebrat, pokud váš kód čeká na asynchronní úlohu.
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;
}
}
Předchozí příklad lze také implementovat jako třídu.
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;
}
}
Některou z předchozích implementací použitých v komponentě:
<CustomErrorBoundary>
...
</CustomErrorBoundary>
Alternativní globální zpracování výjimek
Přístup popsaný v této části platí pro Blazor Server, Blazor WebAssemblya Blazor Web Apps, které přijímají globální interaktivní režim vykreslování (InteractiveServer
, InteractiveWebAssembly
nebo InteractiveAuto
). Tento přístup nefunguje s Blazor Web Apprežimy vykreslování jednotlivých stránek nebo komponent nebo statickým vykreslováním na straně serveru (statické SSR), protože přístup spoléhá na CascadingValue
/CascadingParameter
, který nefunguje přes hranice režimu vykreslování nebo s komponentami, které přijímají statické SSR.
Alternativou k použití hranic chyb (ErrorBoundary) je předání vlastní chybové komponenty jako podřízeným komponentám CascadingValue
. Výhodou použití komponenty oproti použití vložené služby nebo vlastní implementace protokolovacího modulu je, že kaskádová komponenta může vykreslit obsah a použít styly CSS v případě, že dojde k chybě.
Následující ProcessError
příklad komponenty pouze protokoluje chyby, ale metody komponenty mohou zpracovávat chyby jakýmkoli způsobem vyžadovaným aplikací, včetně použití více metod zpracování chyb.
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();
}
}
Poznámka:
Další informace o RenderFragmentkomponentách ASP.NET CoreRazor.
Při použití tohoto přístupu v komponentě Blazor Web Appotevřete komponentu Routes
a zabalte Router ji se komponentou ProcessError
(<Router>...</Router>
). To umožňuje komponentě ProcessError
kaskádovitě dolů na libovolnou komponentu aplikace, kde ProcessError
je komponenta přijata jako CascadingParameter
.
V Routes.razor
:
<ProcessError>
<Router ...>
...
</Router>
</ProcessError>
Při použití tohoto přístupu v Blazor Server aplikaci nebo Blazor WebAssembly aplikaci komponentu App
otevřete, zabalte komponentu Router (<Router>...</Router>
) do ProcessError
komponenty. To umožňuje komponentě ProcessError
kaskádovitě dolů na libovolnou komponentu aplikace, kde ProcessError
je komponenta přijata jako CascadingParameter
.
V App.razor
:
<ProcessError>
<Router ...>
...
</Router>
</ProcessError>
Zpracování chyb v komponentě:
Označte komponentu
ProcessError
jakoCascadingParameter
součást v@code
bloku. Do ukázkovéCounter
komponenty v aplikaci založené na Blazor šabloně projektu přidejte následujícíProcessError
vlastnost:[CascadingParameter] public ProcessError? ProcessError { get; set; }
Volejte metodu zpracování chyb v libovolném
catch
bloku s odpovídajícím typem výjimky. UkázkováProcessError
komponenta nabízí pouze jednuLogError
metodu, ale komponenta zpracování chyb může poskytnout libovolný počet metod zpracování chyb, které řeší alternativní požadavky na zpracování chyb v celé aplikaci. NásledujícíCounter
příklad bloku komponenty@code
obsahujeProcessError
kaskádový parametr a sloučí výjimku pro protokolování, pokud je počet větší než pět:@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); } } }
Zaprotokolovaná chyba:
fail: {COMPONENT NAMESPACE}.ProcessError[0]
ProcessError.LogError: System.InvalidOperationException Message: Current count is over five!
Pokud se LogError
metoda přímo účastní vykreslování, například zobrazení vlastního panelu chybových zpráv nebo změna stylů CSS vykreslených prvků, volání StateHasChanged
na konci LogError
metody pro opětovné vykreslení uživatelského rozhraní.
Protože přístupy v této části zpracovávají chyby pomocí try-catch
příkazu, připojení aplikace SignalR mezi klientem a serverem není přerušeno, když dojde k chybě a okruh zůstane aktivní. Ostatní neošetřené výjimky zůstávají pro okruh závažnou. Další informace najdete v části o tom, jak okruh reaguje na neošetřené výjimky.
Aplikace může použít komponentu zpracování chyb jako kaskádovou hodnotu ke zpracování chyb centralizovaným způsobem.
Následující ProcessError
komponenta se předává jako podřízené CascadingValue
komponenty. Následující příklad pouze protokoluje chybu, ale metody komponenty mohou zpracovávat chyby jakýmkoli způsobem vyžadovaným aplikací, včetně použití více metod zpracování chyb. Výhodou použití komponenty oproti použití vložené služby nebo vlastní implementace protokolovacího modulu je, že kaskádová komponenta může vykreslit obsah a použít styly CSS v případě, že dojde k chybě.
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);
}
}
Poznámka:
Další informace o RenderFragmentkomponentách ASP.NET CoreRazor.
V této komponentě App
zabalte Router komponentu s komponentou ProcessError
. To umožňuje komponentě ProcessError
kaskádovitě dolů na libovolnou komponentu aplikace, kde ProcessError
je komponenta přijata jako CascadingParameter
.
App.razor
:
<ProcessError>
<Router ...>
...
</Router>
</ProcessError>
Zpracování chyb v komponentě:
Označte komponentu
ProcessError
jakoCascadingParameter
součást v@code
bloku:[CascadingParameter] public ProcessError ProcessError { get; set; }
Volejte metodu zpracování chyb v libovolném
catch
bloku s odpovídajícím typem výjimky. UkázkováProcessError
komponenta nabízí pouze jednuLogError
metodu, ale komponenta zpracování chyb může poskytnout libovolný počet metod zpracování chyb, které řeší alternativní požadavky na zpracování chyb v celé aplikaci.try { ... } catch (Exception ex) { ProcessError.LogError(ex); }
Pomocí předchozí ukázkové ProcessError
komponenty a LogError
metody označuje konzola vývojářských nástrojů prohlížeče zachycenou zaprotokolovanou chybu:
fail: {COMPONENT NAMESPACE}.Shared.ProcessError[0]
ProcessError.LogError: System.NullReferenceException Message: Object reference not set to an instance of an object.
Pokud se LogError
metoda přímo účastní vykreslování, například zobrazení vlastního panelu chybových zpráv nebo změna stylů CSS vykreslených prvků, volání StateHasChanged
na konci LogError
metody pro opětovné vykreslení uživatelského rozhraní.
Protože přístupy v této části zpracovávají chyby pomocí try-catch
příkazu, připojení aplikace SignalR mezi klientem a serverem není přerušeno, Blazor když dojde k chybě a okruh zůstane aktivní. Jakákoli neošetřená výjimka je pro okruh závažná. Další informace najdete v části o tom, jak okruh reaguje na neošetřené výjimky.
Chyby protokolu s trvalým zprostředkovatelem
Pokud dojde k neošetřené výjimce, zaprotokoluje ILogger se do instancí nakonfigurovaných v kontejneru služby. Blazor Výstup konzoly protokolu aplikací s zprostředkovatelem protokolování konzoly. Zvažte protokolování do umístění na serveru (nebo back-endovém webovém rozhraní API pro aplikace na straně klienta) s poskytovatelem, který spravuje velikost protokolu a obměnu protokolů. Případně může aplikace používat službu Application Performance Management (APM), například Aplikace Azure lication Insights (Azure Monitor).
Poznámka:
Nativní funkce Application Insights , které podporují aplikace na straně klienta a nativní Blazor podporu rozhraní pro Google Analytics , můžou být dostupné v budoucích verzích těchto technologií. Další informace najdete v tématu Podpora App Insights na Blazor straně klienta WASM (microsoft/ApplicationInsights-dotnet #2143) a webovou analýzu a diagnostiku (včetně odkazů na komunitní implementace) (dotnet/aspnetcore #5461). Mezitím může aplikace na straně klienta používat sadu Application Insights JavaScript SDK s JS interoperabilitou k protokolování chyb přímo do Application Insights z aplikace na straně klienta.
Během vývoje aplikace Blazor , která pracuje přes okruh, aplikace obvykle odesílá úplné podrobnosti o výjimkách do konzoly prohlížeče, aby pomohla při ladění. V produkčním prostředí se podrobné chyby neodesílají klientům, ale úplné podrobnosti o výjimce se protokolují na serveru.
Musíte se rozhodnout, které incidenty se mají protokolovat, a úroveň závažnosti protokolovaných incidentů. Nehostinní uživatelé můžou záměrně aktivovat chyby. Například nezaznamujte incident z chyby, kdy je v adrese URL komponenty, která zobrazuje podrobnosti o produktu, zadaná neznámá ProductId
. Ne všechny chyby by se měly považovat za incidenty pro protokolování.
Další informace najdete v následujících článcích:
- Protokolování ASP.NET Core Blazor
- Zpracování chyb v ASP.NET Core}
- Vytváření webových rozhraní API pomocí ASP.NET Core
•Platí pro aplikace na straně Blazor serveru a další aplikace na straně serveru ASP.NET Core, které jsou back-endové aplikace webového rozhraní API pro Blazor. Aplikace na straně klienta můžou vystihot a odesílat informace o chybách klienta do webového rozhraní API, které protokoluje informace o chybách do trvalého zprostředkovatele protokolování.
Pokud dojde k neošetřené výjimce, zaprotokoluje ILogger se do instancí nakonfigurovaných v kontejneru služby. Blazor Výstup konzoly protokolu aplikací s zprostředkovatelem protokolování konzoly. Zvažte protokolování do trvalejšího umístění na serveru odesláním informací o chybách do back-endového webového rozhraní API, které používá zprostředkovatele protokolování se správou velikostí protokolu a obměnou protokoly. Případně může back-endová webová aplikace API používat službu Application Performance Management (APM), jako je Aplikace Azure lication Insights (Azure Monitor)†, k zaznamenávání informací o chybách, které obdrží od klientů.
Musíte se rozhodnout, které incidenty se mají protokolovat, a úroveň závažnosti protokolovaných incidentů. Nehostinní uživatelé můžou záměrně aktivovat chyby. Například nezaznamujte incident z chyby, kdy je v adrese URL komponenty, která zobrazuje podrobnosti o produktu, zadaná neznámá ProductId
. Ne všechny chyby by se měly považovat za incidenty pro protokolování.
Další informace najdete v následujících článcích:
- Protokolování ASP.NET Core Blazor
- Zpracování chyb v ASP.NET Core}
- Vytváření webových rozhraní API pomocí ASP.NET Core
†Nativní funkce Application Insights , které podporují aplikace na straně klienta a nativní Blazor podporu rozhraní pro Google Analytics , mohou být dostupné v budoucích verzích těchto technologií. Další informace najdete v tématu Podpora App Insights na Blazor straně klienta WASM (microsoft/ApplicationInsights-dotnet #2143) a webovou analýzu a diagnostiku (včetně odkazů na komunitní implementace) (dotnet/aspnetcore #5461). Mezitím může aplikace na straně klienta používat sadu Application Insights JavaScript SDK s JS interoperabilitou k protokolování chyb přímo do Application Insights z aplikace na straně klienta.
•Platí pro aplikace na straně serveru ASP.NET Core, které jsou back-endové aplikace webového rozhraní API pro Blazor aplikace. Aplikace na straně klienta soutisknou a odesílají informace o chybách do webového rozhraní API, které protokoluje informace o chybě do trvalého zprostředkovatele protokolování.
Místa, kde mohou nastat chyby
Kód architektury a aplikace může aktivovat neošetřené výjimky v některém z následujících umístění, které jsou popsány dále v následujících částech tohoto článku:
Vytváření instancí komponent
Při Blazor vytváření instance komponenty:
- Vyvolá se konstruktor komponenty.
- Konstruktory služeb DI poskytované konstruktoru komponenty prostřednictvím
@inject
direktivy nebo atributu[Inject]
jsou vyvolány.
Chyba v spuštěném konstruktoru nebo setter pro libovolnou [Inject]
vlastnost má za následek neošetřenou výjimku a zastaví architekturu v vytvoření instance komponenty. Pokud aplikace pracuje přes okruh, okruh selže. Pokud logika konstruktoru může vyvolat výjimky, měla by aplikace výjimku spojit pomocí try-catch
příkazu s zpracováním chyb a protokolováním.
Metody životního cyklu
Během životnosti komponenty Blazor vyvolá metody životního cyklu. Pokud nějaká metoda životního cyklu vyvolá výjimku, synchronně nebo asynchronně, je výjimka pro okruh závažná. Aby komponenty řešily chyby v metodách životního cyklu, přidejte logiku zpracování chyb.
V následujícím příkladu, kde OnParametersSetAsync volá metodu pro získání produktu:
- Výjimku vyvolanou v
ProductRepository.GetProductByIdAsync
metodě zpracovávátry-catch
příkaz. catch
Při spuštění bloku:loadFailed
je nastavena natrue
hodnotu , která slouží k zobrazení chybové zprávy uživateli.- Chyba se zaprotokoluje.
@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);
}
}
Logika vykreslování
Deklarativní kód v Razor souboru komponenty (.razor
) je zkompilován do metody jazyka C# volaný BuildRenderTree. Když se komponenta vykreslí, BuildRenderTree spustí a sestaví datovou strukturu popisující prvky, text a podřízené součásti vykreslené komponenty.
Logika vykreslování může vyvolat výjimku. Příkladem tohoto scénáře je @someObject.PropertyName
vyhodnocení, ale @someObject
je null
. U Blazor aplikací, které pracují přes okruh, je neošetřená výjimka vyvolaná logikou vykreslování pro okruh aplikace závažná.
Pokud chcete zabránit NullReferenceException v logice vykreslování, zkontrolujte null
objekt před přístupem ke svým členům. V následujícím příkladu nejsou vlastnosti přístupné, person.Address
pokud person.Address
je 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>
}
Předchozí kód předpokládá, že person
není null
. Struktura kódu často zaručuje, že objekt existuje v době vykreslení komponenty. V takových případech není nutné zkontrolovat null
logiku vykreslování. V předchozím příkladu může být zaručeno, že existuje, person
protože person
se vytvoří při vytvoření instance komponenty, jak ukazuje následující příklad:
@code {
private Person person = new();
...
}
Obslužné rutiny událostí
Kód na straně klienta aktivuje vyvolání kódu V# při vytváření obslužných rutin událostí pomocí:
@onclick
@onchange
- Další
@on...
atributy @bind
Kód obslužné rutiny události může v těchto scénářích vyvolat neošetřenou výjimku.
Pokud aplikace volá kód, který by mohl selhat z externích důvodů, vyvolá výjimku pomocí try-catch
příkazu s zpracováním chyb a protokolováním.
Pokud obslužná rutina události vyvolá neošetřenou výjimku (například databázový dotaz selže), která není zachycená a zpracována kódem vývojáře:
- Architektura zaznamená výjimku.
- Blazor V aplikaci, která pracuje přes okruh, je výjimka pro okruh aplikace závažná.
Vyřazení součástí
Součást může být například odebrána z uživatelského rozhraní, protože uživatel přešel na jinou stránku. Pokud je komponenta, která implementuje System.IDisposable , odebrána z uživatelského rozhraní, volá rozhraní metodu Dispose komponenty.
Pokud metoda komponenty Dispose
vyvolá neošetřenou výjimku v Blazor aplikaci, která pracuje přes okruh, je pro okruh aplikace závažná.
Pokud logika odstranění může vyvolat výjimky, měla by aplikace výjimku spojit pomocí try-catch
příkazu s zpracováním chyb a protokolováním.
Další informace o odstranění součástí najdete v tématu ASP.NET životní Razor cyklus základních komponent.
Interoperabilita JavaScriptu
IJSRuntime je registrován v Blazor rámci. IJSRuntime.InvokeAsync umožňuje kódu .NET provádět asynchronní volání modulu runtime JavaScriptu (JS) v prohlížeči uživatele.
Následující podmínky platí pro zpracování chyb s InvokeAsync:
- Pokud volání selže InvokeAsync synchronně, dojde k výjimce .NET. Volání InvokeAsync může například selhat, protože zadané argumenty nelze serializovat. Vývojářský kód musí zachytit výjimku. Pokud kód aplikace v obslužné rutině události nebo metodě životního cyklu komponent nezpracuje výjimku v aplikaci, která Blazor pracuje přes okruh, je výsledná výjimka pro okruh aplikace závažná.
- Pokud volání selže InvokeAsync asynchronně, rozhraní .NET Task selže. Volání může selhat InvokeAsync , například proto, že JSkód -side vyvolá výjimku nebo vrátí dokončené
Promise
jakorejected
. Vývojářský kód musí zachytit výjimku. Pokud používáteawait
operátor, zvažte zabalení volání metody dotry-catch
příkazu s zpracováním chyb a protokolováním. Jinak v Blazor aplikaci, která pracuje přes okruh, vede chybný kód k neošetřené výjimce, která je závažná pro okruh aplikace. - Volání, která se InvokeAsync mají dokončit během určitého období, nebo jinak vyprší časový limit volání. Výchozí časový limit je jedna minuta. Časový limit chrání kód před ztrátou síťového připojení nebo JS kódu, který nikdy neodesílá zprávu o dokončení. Pokud vyprší časový limit volání, výsledek System.Threading.Tasks selže s chybou OperationCanceledException. Soutisk a zpracování výjimky s protokolováním
JS Podobně může kód inicializovat volání metod .NET označených atributem[JSInvokable]
. Pokud tyto metody .NET vyvolá neošetřenou výjimku:
- Blazor V aplikaci, která pracuje přes okruh, není výjimka považována za závažnou pro okruh aplikace.
- Strana JS-side
Promise
je odmítnuta.
Máte možnost použít kód zpracování chyb na straně .NET nebo JS na straně volání metody.
Další informace najdete v následujících článcích:
- Volání funkcí JavaScriptu z metod .NET v ASP.NET Core Blazor
- Volání metod .NET z funkcí JavaScriptu v ASP.NET Core Blazor
Předkreslování
Razor komponenty jsou ve výchozím nastavení předem vytyčovány tak, aby se jejich vykreslené kódy HTML vrátily jako součást počátečního požadavku HTTP uživatele.
Blazor V aplikaci, která pracuje přes okruh, funguje prerendering podle:
- Vytvoření nového okruhu pro všechny předem připravené součásti, které jsou součástí stejné stránky.
- Generuje se počáteční kód HTML.
- S okruhem zacházíte tak, dokud
disconnected
prohlížeč uživatele nenaváže SignalR připojení zpět ke stejnému serveru. Po navázání připojení se obnoví interaktivita okruhu a aktualizuje se kód HTML komponent.
U předem vytyčovaných komponent na straně klienta funguje předkreslování:
- Generování počátečního kódu HTML na serveru pro všechny předsdílené komponenty, které jsou součástí stejné stránky.
- Vytvoření interaktivní komponenty na klientovi po načtení zkompilovaného kódu aplikace a modulu runtime .NET (pokud ještě není načteno) na pozadí.
Pokud komponenta při předřazení vyvolá neošetřenou výjimku, například během metody životního cyklu nebo v logice vykreslování:
- Blazor V aplikaci, která pracuje přes okruh, je výjimka pro okruh závažná. U předsekvenovaných komponent na straně klienta výjimka zabraňuje vykreslení komponenty.
- Výjimka vyvolá zásobník volání z objektu ComponentTagHelper.
Za normálních okolností, když se předdekretování nezdaří, nebude nadále sestavovat a vykreslovat komponentu, protože pracovní komponentu nelze vykreslit.
Aby bylo možné tolerovat chyby, ke kterým může dojít během předkreslování, musí být logika zpracování chyb umístěna uvnitř komponenty, která může vyvolat výjimky. Používejte try-catch
příkazy se zpracováním chyb a protokolováním. Místo zabalení příkazu ComponentTagHelper try-catch
do příkazu umístěte logiku zpracování chyb v komponentě vykreslené ComponentTagHelpersadou .
Pokročilé scénáře
Rekurzivní vykreslování
Komponenty se dají vnořit rekurzivně. To je užitečné pro reprezentaci rekurzivních datových struktur. Například komponenta TreeNode
může vykreslit více TreeNode
komponent pro každou podřízenou položku uzlu.
Při rekurzivním vykreslování se vyhněte vzorům kódování, které vedou k nekonečné rekurzi:
- Nevykreslujte rekurzivně datovou strukturu, která obsahuje cyklus. Například nevykreslujte uzel stromu, jehož podřízené položky se zahrnují.
- Nevytvávejte řetězec rozložení, která obsahují cyklus. Například nevytvořte rozložení, jehož rozložení je samotné.
- Nepovolujte koncovému uživateli porušení invariantů rekurze (pravidel) prostřednictvím škodlivých datových zadávání nebo volání interop JavaScriptu.
Nekonečné smyčky během vykreslování:
- Způsobí, že proces vykreslování bude pokračovat navždy.
- Je ekvivalentní vytvoření neukončené smyčky.
V těchto scénářích se Blazor selhání a obvykle se pokouší:
- Spotřebovávejte tolik času procesoru, kolik povoluje operační systém, neomezeně dlouho.
- Spotřebovávat neomezené množství paměti. Využívání neomezené paměti odpovídá scénáři, kdy neukončená smyčka přidává položky do kolekce při každé iteraci.
Abyste se vyhnuli nekonečným rekurzivním vzorcům, ujistěte se, že rekurzivní kód vykreslování obsahuje vhodné podmínky zastavení.
Vlastní logika stromu vykreslování
Většina Razor komponent se implementuje jako Razor soubory komponent (.razor
) a jsou zkompilovány architekturou za účelem vytvoření logiky, která pracuje s vykreslením RenderTreeBuilder jejich výstupu. Vývojář však může ručně implementovat RenderTreeBuilder logiku pomocí procedurálního kódu jazyka C#. Další informace najdete v tématu ASP.NET Blazor pokročilých scénářích (vytváření stromové struktury vykreslování).
Upozorňující
Použití logiky ručního tvůrce stromové struktury vykreslování se považuje za pokročilý a nebezpečný scénář, nedoporučuje se pro obecný vývoj komponent.
Pokud RenderTreeBuilder je kód napsaný, vývojář musí zaručit správnost kódu. Vývojář například musí zajistit, aby:
- Volání a OpenElement CloseElement jsou správně vyvážená.
- Atributy se přidají pouze na správných místech.
Nesprávná logika ručního tvůrce stromu vykreslování může způsobit libovolné nedefinované chování, včetně chybových ukončení, aplikace nebo serveru, aby přestaly reagovat, a ohrožení zabezpečení.
Zvažte ruční logiku tvůrce stromové struktury na stejné úrovni složitosti a se stejnou úrovní nebezpečí jako ruční psaní kódu sestavení nebo pokynů jazyka MSIL (Microsoft Intermediate Language).
Další materiály
†Applies k back-endu ASP.NET aplikacím core webového rozhraní API, které aplikace na straně Blazor klienta používají k protokolování.