Obsługa błędów w Blazor aplikacjach ASP.NET CoreHandle errors in ASP.NET Core Blazor apps

W tym artykule opisano, jak Blazor zarządzać nieobsługiwanymi wyjątkami oraz jak opracowywać aplikacje wykrywające i obsługujące błędy.This article describes how Blazor manages unhandled exceptions and how to develop apps that detect and handle errors.

Szczegóły błędów podczas opracowywaniaDetailed errors during development

Gdy Blazor aplikacja nie działa prawidłowo podczas opracowywania, otrzymuje szczegółowe informacje o błędzie z aplikacji, które pomagają w rozwiązywaniu problemów i rozwiązaniu problemu.When a Blazor app isn't functioning properly during development, receiving detailed error information from the app assists in troubleshooting and fixing the issue. Gdy wystąpi błąd, Blazor w dolnej części ekranu aplikacje są wyświetlane żółte paski:When an error occurs, Blazor apps display a light yellow bar at the bottom of the screen:

  • Podczas tworzenia pasek kieruje użytkownika do konsoli przeglądarki, gdzie można zobaczyć wyjątek.During development, the bar directs you to the browser console, where you can see the exception.
  • W środowisku produkcyjnym pasek powiadamia użytkownika o wystąpieniu błędu i zaleca odświeżenie przeglądarki.In production, the bar notifies the user that an error has occurred and recommends refreshing the browser.

Interfejs użytkownika dla tego środowiska obsługi błędów jest częścią Blazor szablonów projektu.The UI for this error handling experience is part of the Blazor project templates.

W Blazor WebAssembly aplikacji Dostosuj środowisko w wwwroot/index.html pliku:In a Blazor WebAssembly app, customize the experience in the wwwroot/index.html file:

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

blazor-error-uiElement jest zwykle ukryty z powodu obecności display: none stylu blazor-error-ui klasy CSS w arkuszu stylów aplikacji ( wwwroot/css/app.css ).The blazor-error-ui element is normally hidden due the presence of the display: none style of the blazor-error-ui CSS class in the app's stylesheet (wwwroot/css/app.css). Gdy wystąpi błąd, struktura ma zastosowanie display: block do elementu.When an error occurs, the framework applies display: block to the element.

Zarządzanie nieobsługiwanymi wyjątkami w kodzie deweloperaManage unhandled exceptions in developer code

Aby aplikacja kontynuowała działanie po wystąpieniu błędu, aplikacja musi mieć logikę obsługi błędów.For an app to continue after an error, the app must have error handling logic. W dalszej części tego artykułu opisano potencjalne źródła nieobsłużonych wyjątków.Later sections of this article describe potential sources of unhandled exceptions.

W środowisku produkcyjnym nie Renderuj komunikatów wyjątków struktury ani śladów stosu w interfejsie użytkownika.In production, don't render framework exception messages or stack traces in the UI. Renderowanie komunikatów o wyjątkach lub śladów stosu może:Rendering exception messages or stack traces could:

  • Ujawnianie poufnych informacji użytkownikom końcowym.Disclose sensitive information to end users.
  • Pomóż złośliwemu użytkownikowi wykrywać słabe strony w aplikacji, która może naruszyć bezpieczeństwo aplikacji, serwera lub sieci.Help a malicious user discover weaknesses in an app that can compromise the security of the app, server, or network.

Globalna obsługa wyjątkówGlobal exception handling

Blazor jest strukturą po stronie klienta jednostronicowej aplikacji (SPA).Blazor is a single-page application (SPA) client-side framework. Przeglądarka pełni rolę hosta aplikacji i w ten sposób działa jako potok przetwarzania poszczególnych Razor składników w oparciu o żądania URI dotyczące nawigacji i zasobów statycznych.The browser serves as the app's host and thus acts as the processing pipeline for individual Razor components based on URI requests for navigation and static assets. W przeciwieństwie do ASP.NET Core aplikacji uruchamianych na serwerze z potokiem przetwarzania oprogramowania pośredniczącego, nie istnieje potok oprogramowania pośredniczącego, który przetwarza żądania dotyczące Razor składników, których można użyć do obsługi błędów globalnych.Unlike ASP.NET Core apps that run on the server with a middleware processing pipeline, there is no middleware pipeline that processes requests for Razor components that can be leveraged for global error handling. Jednak aplikacja może używać składnika przetwarzania błędów jako wartości kaskadowej do przetwarzania błędów w scentralizowany sposób.However, an app can use an error processing component as a cascading value to process errors in a centralized way.

Poniższy Error składnik przekazuje sam siebie jako CascadingValue składnik do elementów podrzędnych.The following Error component passes itself as a CascadingValue to child components. Poniższy przykład powoduje jedynie rejestrowanie błędu, ale metody składnika mogą przetwarzać błędy w dowolny sposób wymagany przez aplikację, w tym za pomocą wielu metod przetwarzania błędów.The following example merely logs the error, but methods of the component can process errors in any way required by the app, including through the use of multiple error processing methods. Zaletą korzystania z składnika przez użycie wstrzykniętej usługi lub niestandardowej implementacji rejestratora jest to, że składnik kaskadowy może renderować zawartość i stosować style CSS w przypadku wystąpienia błędu.An advantage of using a component over using an injected service or a custom logger implementation is that a cascaded component can render content and apply CSS styles when an error occurs.

Shared/Error.razor:Shared/Error.razor:

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

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

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

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

W App składniku zawiń składnik na składnik Router Error .In the App component, wrap the Router component with the Error component. Pozwala to Error składnikowi na kaskadowe umieszczanie w dowolnym składniku aplikacji, w której Error składnik został odebrany jako CascadingParameter .This permits the Error component to cascade down to any component of the app where the Error component is received as a CascadingParameter.

App.razor:App.razor:

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

Aby przetworzyć błędy w składniku:To process errors in a component:

  • Wyznacz Error składnik jako CascadingParameter w @code bloku:Designate the Error component as a CascadingParameter in the @code block:

    [CascadingParameter]
    public Error Error { get; set; }
    
  • Wywołaj metodę przetwarzania błędu w dowolnym catch bloku z odpowiednim typem wyjątku.Call an error processing method in any catch block with an appropriate exception type. Przykładowy Error składnik oferuje tylko jedną ProcessError metodę, ale składnik przetwarzania błędów może zapewnić dowolną liczbę metod przetwarzania błędów, aby rozwiązać alternatywne wymagania dotyczące przetwarzania błędów w całej aplikacji.The example Error component only offers a single ProcessError method, but the error processing component can provide any number of error processing methods to address alternative error processing requirements throughout the app.

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

Korzystając z powyższego przykładowego Error składnika i ProcessError metody, konsola narzędzi deweloperskich w przeglądarce wskazuje zarejestrowanego błędu:Using the preceding example Error component and ProcessError method, the browser's developer tools console indicates the trapped, logged error:

Niepowodzenie: Blazor Sample. Shared. Error [0] Error: ProcessError-Type: System. NullReferenceException Message: odwołanie do obiektu nie jest ustawione na wystąpienie obiektu.fail: BlazorSample.Shared.Error[0] Error:ProcessError - Type: System.NullReferenceException Message: Object reference not set to an instance of an object.

Jeśli ProcessError Metoda bezpośrednio uczestniczy w renderowaniu, na przykład wyświetlając niestandardowy pasek komunikatów o błędach lub zmieniając style CSS renderowane elementy, wywołaj StateHasChanged na końcu ProcessErrors metody, aby przetworzyć interfejs użytkownika.If the ProcessError method directly participates in rendering, such as showing a custom error message bar or changing the CSS styles of the rendered elements, call StateHasChanged at the end of the ProcessErrors method to rerender the UI.

Rejestrowanie błędów przez dostawcę trwałegoLog errors with a persistent provider

Jeśli wystąpi nieobsługiwany wyjątek, wyjątek jest rejestrowany w ILogger wystąpieniach skonfigurowanych w kontenerze usługi.If an unhandled exception occurs, the exception is logged to ILogger instances configured in the service container. Domyślnie Blazor aplikacje rejestrują dane wyjściowe konsoli z dostawcą rejestrowania konsoli.By default, Blazor apps log to console output with the Console Logging Provider. Należy rozważyć logowanie do bardziej trwałej lokalizacji na serwerze, wysyłając informacje o błędzie do interfejsu API sieci Web zaplecza, który używa dostawcy rejestrowania z zarządzaniem rozmiarem dziennika i rotacją dzienników.Consider logging to a more permanent location on the server by sending error information to a backend web API that uses a logging provider with log size management and log rotation. Alternatywnie aplikacja interfejsu API sieci Web zaplecza może używać usługi zarządzania wydajnością aplikacji (APM), takiej jak Azure Application Insights (Azure monitor) † , aby rejestrować informacje o błędach odbierane od klientów.Alternatively, the backend web API app can use an Application Performance Management (APM) service, such as Azure Application Insights (Azure Monitor)†, to record error information that it receives from clients.

Należy zdecydować, które zdarzenia mają być rejestrowane, oraz poziom ważności zarejestrowanych zdarzeń.You must decide which incidents to log and the level of severity of logged incidents. Nieszkodliwi użytkownicy mogą być w stanie wyzwolić błędy w sposób celowy.Hostile users might be able to trigger errors deliberately. Na przykład nie należy rejestrować zdarzenia z błędu, gdy ProductId w adresie URL składnika, który zawiera szczegółowe informacje o produkcie.For example, don't log an incident from an error where an unknown ProductId is supplied in the URL of a component that displays product details. Nie wszystkie błędy powinny być traktowane jako zdarzenia do rejestrowania.Not all errors should be treated as incidents for logging.

Aby uzyskać więcej informacji, zobacz następujące artykuły:For more information, see the following articles:

†Natywne funkcje Application Insights obsługujące Blazor WebAssembly aplikacje i natywną Blazor obsługę platformy Google Analytics mogą być dostępne w przyszłych wersjach tych technologii.†Native Application Insights features to support Blazor WebAssembly apps and native Blazor framework support for Google Analytics might become available in future releases of these technologies. Aby uzyskać więcej informacji, zobacz temat Obsługa usługi App Insights na Blazor stronie klienta WASM (Microsoft/ApplicationInsights-dotnet #2143) oraz Web Analytics i Diagnostics (w tym linki do implementacji społeczności) (w #5461 dotnet/aspnetcore).For more information, see Support App Insights in Blazor WASM Client Side (microsoft/ApplicationInsights-dotnet #2143) and Web analytics and diagnostics (includes links to community implementations) (dotnet/aspnetcore #5461). W międzyczasie aplikacja po stronie klienta Blazor WebAssembly może używać Application Insights zestawu SDK języka JavaScript z usługą js Interop do rejestrowania błędów bezpośrednio do Application Insights z aplikacji po stronie klienta.In the meantime, a client-side Blazor WebAssembly app can use the Application Insights JavaScript SDK with JS interop to log errors directly to Application Insights from a client-side app.

‡Dotyczy aplikacji ASP.NET Core po stronie serwera, które są aplikacjami zaplecza interfejsu API sieci Web dla Blazor aplikacji.‡Applies to server-side ASP.NET Core apps that are web API backend apps for Blazor apps. Aplikacje po stronie klienta zalewki i wysyłają informacje o błędach do internetowego interfejsu API, który rejestruje informacje o błędzie dla dostawcy trwałego rejestrowania.Client-side apps trap and send error information to a web API, which logs the error information to a persistent logging provider.

Miejsca, w których mogą wystąpić błędyPlaces where errors may occur

Kod struktury i aplikacji może wyzwolić Nieobsłużone wyjątki w następujących lokalizacjach, które opisano w następujących sekcjach tego artykułu:Framework and app code may trigger unhandled exceptions in any of the following locations, which are described further in the following sections of this article:

Tworzenie wystąpienia składnikaComponent instantiation

Podczas Blazor tworzenia wystąpienia składnika:When Blazor creates an instance of a component:

  • Konstruktor składnika jest wywoływany.The component's constructor is invoked.
  • Konstruktory wszelkich niepojedynczych usług DI dostarczonych do konstruktora składnika za pośrednictwem @inject dyrektywy lub [Inject] atrybutu są wywoływane.The constructors of any non-singleton DI services supplied to the component's constructor via the @inject directive or the [Inject] attribute are invoked.

Błąd w wykonanym konstruktorze lub Metoda ustawiająca dla dowolnej [Inject] właściwości powoduje nieobsłużony wyjątek i uniemożliwia utworzenie wystąpienia składnika przez strukturę.An error in an executed constructor or a setter for any [Inject] property results in an unhandled exception and stops the framework from instantiating the component. Jeśli logika konstruktora może generować wyjątki, aplikacja powinna zalewkować wyjątki przy użyciu try-catch instrukcji z obsługą błędów i rejestrowaniem.If constructor logic may throw exceptions, the app should trap the exceptions using a try-catch statement with error handling and logging.

Metody cyklu życiaLifecycle methods

W okresie istnienia składnika Blazor wywołuje metody cyklu życia.During the lifetime of a component, Blazor invokes lifecycle methods. Aby składniki zajmowały błędy w metodach cyklu życia, Dodaj logikę obsługi błędów.For components to deal with errors in lifecycle methods, add error handling logic.

W poniższym przykładzie, gdzie OnParametersSetAsync wywołuje metodę w celu uzyskania produktu:In the following example where OnParametersSetAsync calls a method to obtain a product:

  • Wyjątek zgłoszony w ProductRepository.GetProductByIdAsync metodzie jest obsługiwany przez try-catch instrukcję.An exception thrown in the ProductRepository.GetProductByIdAsync method is handled by a try-catch statement.
  • Gdy catch blok jest wykonywany:When the catch block is executed:
    • loadFailed jest ustawiona na true , która jest używana do wyświetlania komunikatu o błędzie dla użytkownika.loadFailed is set to true, which is used to display an error message to the user.
    • Błąd jest rejestrowany.The error is logged.
@page "/product-details/{ProductId:int}"
@using Microsoft.Extensions.Logging
@inject IProductRepository ProductRepository
@inject ILogger<ProductDetails> Logger

@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;
            details = await ProductRepository.GetProductByIdAsync(ProductId);
        }
        catch (Exception ex)
        {
            loadFailed = true;
            Logger.LogWarning(ex, "Failed to load product {ProductId}", ProductId);
        }
    }
}
@page "/product-details/{ProductId:int}"
@using Microsoft.Extensions.Logging
@inject IProductRepository ProductRepository
@inject ILogger<ProductDetails> Logger

@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;
            details = await ProductRepository.GetProductByIdAsync(ProductId);
        }
        catch (Exception ex)
        {
            loadFailed = true;
            Logger.LogWarning(ex, "Failed to load product {ProductId}", ProductId);
        }
    }
}

Logika renderowaniaRendering logic

Znaczniki deklaratywne w Razor pliku składnika ( .razor ) są kompilowane do metody języka C# o nazwie BuildRenderTree .The declarative markup in a Razor component file (.razor) is compiled into a C# method called BuildRenderTree. Gdy składnik renderuje, BuildRenderTree wykonuje i tworzy strukturę danych opisującą elementy, tekst i składniki podrzędne renderowanego składnika.When a component renders, BuildRenderTree executes and builds up a data structure describing the elements, text, and child components of the rendered component.

Logika renderowania może zgłosić wyjątek.Rendering logic can throw an exception. Przykład tego scenariusza występuje, gdy @someObject.PropertyName jest oceniane, ale @someObject jest null .An example of this scenario occurs when @someObject.PropertyName is evaluated but @someObject is null.

Aby uniknąć NullReferenceException renderowania logiki, null przed uzyskaniem dostępu do elementów członkowskich Sprawdź, czy jest on obiektem.To prevent a NullReferenceException in rendering logic, check for a null object before accessing its members. W poniższym przykładzie person.Address właściwości nie są dostępne, jeśli person.Address null :In the following example, person.Address properties aren't accessed if 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>
}
@if (person.Address != null)
{
    <div>@person.Address.Line1</div>
    <div>@person.Address.Line2</div>
    <div>@person.Address.City</div>
    <div>@person.Address.Country</div>
}

Poprzedni kod założono, że person nie jest null .The preceding code assumes that person isn't null. Często Struktura kodu gwarantuje, że obiekt istnieje w momencie renderowania składnika.Often, the structure of the code guarantees that an object exists at the time the component is rendered. W takich przypadkach nie jest konieczne sprawdzanie null logiki renderowania.In those cases, it isn't necessary to check for null in rendering logic. W poprzednim przykładzie person można zagwarantować, że istnieje, ponieważ person jest tworzony podczas tworzenia wystąpienia składnika, jak pokazano na poniższym przykładzie:In the prior example, person might be guaranteed to exist because person is created when the component is instantiated, as the following example shows:

@code {
    private Person person = new();

    ...
}
@code {
    private Person person = new Person();

    ...
}

Procedury obsługi zdarzeńEvent handlers

Kod po stronie klienta wyzwala wywołania kodu C#, gdy programy obsługi zdarzeń są tworzone przy użyciu:Client-side code triggers invocations of C# code when event handlers are created using:

  • @onclick
  • @onchange
  • Inne @on... atrybutyOther @on... attributes
  • @bind

Kod procedury obsługi zdarzeń może zgłosić nieobsługiwany wyjątek w tych scenariuszach.Event handler code might throw an unhandled exception in these scenarios.

Jeśli aplikacja wywołuje kod, który może zakończyć się niepowodzeniem z powodów zewnętrznych, należy zastosować wyjątek pułapki przy użyciu try-catch instrukcji z obsługą błędów i rejestrowaniem.If the app calls code that could fail for external reasons, trap exceptions using a try-catch statement with error handling and logging.

Jeśli kod użytkownika nie pułapki i obsłuży wyjątek, struktura rejestruje wyjątek.If user code doesn't trap and handle the exception, the framework logs the exception.

Usuwanie składnikówComponent disposal

Składnik może zostać usunięty z interfejsu użytkownika, na przykład, ponieważ użytkownik przeszedł do innej strony.A component may be removed from the UI, for example, because the user has navigated to another page. Gdy składnik implementujący System.IDisposable jest usuwany z interfejsu użytkownika, struktura wywołuje Dispose metodę składnika.When a component that implements System.IDisposable is removed from the UI, the framework calls the component's Dispose method.

Jeśli logika usuwania może generować wyjątki, aplikacja powinna zalewkować wyjątki przy użyciu try-catch instrukcji z obsługą błędów i rejestrowaniem.If disposal logic may throw exceptions, the app should trap the exceptions using a try-catch statement with error handling and logging.

Aby uzyskać więcej informacji na temat usuwania składników, zobacz ASP.NET Podstawowy Razor cykl życia składnika .For more information on component disposal, see ASP.NET Podstawowy Razor cykl życia składnika.

Międzyoperacyjność w języku JavaScriptJavaScript interop

IJSRuntime.InvokeAsync umożliwia programowi .NET Code wykonywanie wywołań asynchronicznych do środowiska uruchomieniowego JavaScript w przeglądarce użytkownika.IJSRuntime.InvokeAsync allows .NET code to make asynchronous calls to the JavaScript runtime in the user's browser.

Poniższe warunki dotyczą obsługi błędów w programie InvokeAsync :The following conditions apply to error handling with InvokeAsync:

  • Jeśli wywołanie InvokeAsync synchronicznie zakończy się niepowodzeniem, wystąpi wyjątek programu .NET.If a call to InvokeAsync fails synchronously, a .NET exception occurs. Wywołanie InvokeAsync może zakończyć się niepowodzeniem, na przykład dlatego, że nie można serializować dostarczonych argumentów.A call to InvokeAsync may fail, for example, because the supplied arguments can't be serialized. Kod dewelopera musi przechwycić wyjątek.Developer code must catch the exception.
  • Jeśli wywołanie InvokeAsync powiedzie się asynchronicznie, .NET Task kończy się niepowodzeniem.If a call to InvokeAsync fails asynchronously, the .NET Task fails. Wywołanie InvokeAsync może zakończyć się niepowodzeniem, na przykład ponieważ kod po stronie JavaScript zgłasza wyjątek lub zwraca Promise , który został ukończony jako rejected .A call to InvokeAsync may fail, for example, because the JavaScript-side code throws an exception or returns a Promise that completed as rejected. Kod dewelopera musi przechwycić wyjątek.Developer code must catch the exception. W przypadku użycia await operatora Rozważ zapakowanie wywołania metody w try-catch instrukcji z obsługą błędów i rejestrowaniem.If using the await operator, consider wrapping the method call in a try-catch statement with error handling and logging.
  • Domyślnie wywołania programu InvokeAsync muszą zakończyć się w określonym przedziale czasu lub w przeciwnym razie upłynął limit czasu połączenia. Domyślny limit czasu wynosi jedną minutę.By default, calls to InvokeAsync must complete within a certain period or else the call times out. The default timeout period is one minute. Limit czasu chroni kod przed utratą połączenia sieciowego lub kodem JavaScript, który nigdy nie odsyła komunikat uzupełniający.The timeout protects the code against a loss in network connectivity or JavaScript code that never sends back a completion message. Jeśli wystąpiło przełączenie, wynikiem System.Threading.Tasks kończy się niepowodzeniem a OperationCanceledException .If the call times out, the resulting System.Threading.Tasks fails with an OperationCanceledException. Zalewka i przetwórz wyjątek z rejestrowaniem.Trap and process the exception with logging.

Podobnie kod JavaScript może inicjować wywołania metod .NET wskazywanych przez [JSInvokable] atrybut.Similarly, JavaScript code may initiate calls to .NET methods indicated by the [JSInvokable] attribute. Jeśli te metody .NET zgłaszają nieobsłużony wyjątek, po stronie JavaScript Promise zostanie odrzucona.If these .NET methods throw an unhandled exception, the JavaScript-side Promise is rejected.

Istnieje możliwość użycia kodu obsługi błędów po stronie .NET lub stronie JavaScript wywołania metody.You have the option of using error handling code on either the .NET side or the JavaScript side of the method call.

Aby uzyskać więcej informacji, zobacz następujące artykuły:For more information, see the following articles:

Scenariusze zaawansowaneAdvanced scenarios

Renderowanie cykliczneRecursive rendering

Składniki można cyklicznie zagnieżdżać.Components can be nested recursively. Jest to przydatne do reprezentowania struktur danych rekursywnych.This is useful for representing recursive data structures. Na przykład TreeNode składnik może renderować więcej TreeNode składników dla każdego węzła podrzędnego.For example, a TreeNode component can render more TreeNode components for each of the node's children.

W przypadku renderowania cyklicznego należy unikać tworzenia wzorców, które powodują nieskończoną rekursję:When rendering recursively, avoid coding patterns that result in infinite recursion:

  • Nie Renderuj rekursywnie struktury danych zawierającej cykl.Don't recursively render a data structure that contains a cycle. Na przykład nie Renderuj węzła drzewa, którego elementy podrzędne zawierają sam siebie.For example, don't render a tree node whose children includes itself.
  • Nie twórz łańcucha układów zawierających cykl.Don't create a chain of layouts that contain a cycle. Na przykład nie twórz układu, którego układ jest sam.For example, don't create a layout whose layout is itself.
  • Nie Zezwalaj użytkownikowi końcowemu na naruszenie nieodmian rekursji (reguł) przy użyciu złośliwego wpisu danych lub wywołań międzyoperacyjnych języka JavaScript.Don't allow an end user to violate recursion invariants (rules) through malicious data entry or JavaScript interop calls.

Nieskończone pętle podczas renderowania:Infinite loops during rendering:

  • Powoduje, że proces renderowania kontynuuje działanie zawsze.Causes the rendering process to continue forever.
  • Jest równoznaczny z tworzeniem niezakończonej pętli.Is equivalent to creating an unterminated loop.

W tych scenariuszach wątek zwykle próbuje wykonać:In these scenarios, the thread usually attempts to:

  • Zużywaj ilość czasu procesora CPU dozwoloną przez system operacyjny w nieskończoność.Consume as much CPU time as permitted by the operating system, indefinitely.
  • Korzystaj z nieograniczonej ilości pamięci klienta.Consume an unlimited amount of client memory. Zużywanie nieograniczonej pamięci jest równoważne scenariuszowi, w którym niezakończona pętla dodaje wpisy do kolekcji na każdej iteracji.Consuming unlimited memory is equivalent to the scenario where an unterminated loop adds entries to a collection on every iteration.

Aby uniknąć nieskończonych wzorców rekursji, należy się upewnić, że kod renderowania cyklicznego zawiera odpowiednie warunki zatrzymania.To avoid infinite recursion patterns, ensure that recursive rendering code contains suitable stopping conditions.

Logika drzewa renderowania niestandardowegoCustom render tree logic

Większość Blazor składników jest implementowana jako Razor pliki składników ( .razor ) i są kompilowane przez platformę w celu utworzenia logiki, która działa w RenderTreeBuilder celu renderowania danych wyjściowych.Most Blazor components are implemented as Razor component files (.razor) and are compiled by the framework to produce logic that operates on a RenderTreeBuilder to render their output. Jednak deweloper może ręcznie zaimplementować RenderTreeBuilder logikę przy użyciu procedury kodu w języku C#.However, a developer may manually implement RenderTreeBuilder logic using procedural C# code. Aby uzyskać więcej informacji, zobacz BlazorZaawansowane scenariusze ASP.NET Core.For more information, see BlazorZaawansowane scenariusze ASP.NET Core.

Ostrzeżenie

Korzystanie z logiki konstruktora drzewa renderowania ręcznego jest uznawane za zaawansowane i niebezpieczne scenariusze, które nie są zalecane do ogólnego tworzenia składników.Use of manual render tree builder logic is considered an advanced and unsafe scenario, not recommended for general component development.

Jeśli RenderTreeBuilder kod zostanie zapisany, Deweloper musi zagwarantować poprawność kodu.If RenderTreeBuilder code is written, the developer must guarantee the correctness of the code. Na przykład Deweloper musi upewnić się, że:For example, the developer must ensure that:

  • Wywołania OpenElement i CloseElement są prawidłowo zrównoważone.Calls to OpenElement and CloseElement are correctly balanced.
  • Atrybuty są dodawane tylko w prawidłowych miejscach.Attributes are only added in the correct places.

Nieprawidłowa ręczna logika konstruktora drzewa renderowania może spowodować dowolne niezdefiniowane zachowanie, w tym awarie, zawieszenie aplikacji i luki w zabezpieczeniach.Incorrect manual render tree builder logic can cause arbitrary undefined behavior, including crashes, app hangs, and security vulnerabilities.

Rozważ ręczne renderowanie logiki konstruktora drzew drzewa na tym samym poziomie złożoności i z tym samym poziomem zagrożenia co ręczne pisanie kodu zestawu lub języka pośredniego firmy Microsoft (MSIL) .Consider manual render tree builder logic on the same level of complexity and with the same level of danger as writing assembly code or Microsoft Intermediate Language (MSIL) instructions by hand.

Dodatkowe zasobyAdditional resources

†Dotyczy aplikacji interfejsu API sieci Web ASP.NET Core zaplecza, które są Blazor WebAssembly używane przez aplikacje po stronie klienta do rejestrowania.†Applies to backend ASP.NET Core web API apps that client-side Blazor WebAssembly apps use for logging.

Szczegóły błędów podczas opracowywaniaDetailed errors during development

Gdy Blazor aplikacja nie działa prawidłowo podczas opracowywania, otrzymuje szczegółowe informacje o błędzie z aplikacji, które pomagają w rozwiązywaniu problemów i rozwiązaniu problemu.When a Blazor app isn't functioning properly during development, receiving detailed error information from the app assists in troubleshooting and fixing the issue. Gdy wystąpi błąd, Blazor w dolnej części ekranu aplikacje są wyświetlane żółte paski:When an error occurs, Blazor apps display a light yellow bar at the bottom of the screen:

  • Podczas tworzenia pasek kieruje użytkownika do konsoli przeglądarki, gdzie można zobaczyć wyjątek.During development, the bar directs you to the browser console, where you can see the exception.
  • W środowisku produkcyjnym pasek powiadamia użytkownika o wystąpieniu błędu i zaleca odświeżenie przeglądarki.In production, the bar notifies the user that an error has occurred and recommends refreshing the browser.

Interfejs użytkownika dla tego środowiska obsługi błędów jest częścią Blazor szablonów projektu.The UI for this error handling experience is part of the Blazor project templates.

W Blazor Server aplikacji Dostosuj środowisko w Pages/_Host.cshtml pliku:In a Blazor Server app, customize the experience in the Pages/_Host.cshtml file:

<div id="blazor-error-ui">
    <environment include="Staging,Production">
        An error has occurred. This application may no longer respond until reloaded.
    </environment>
    <environment include="Development">
        An unhandled exception has occurred. See browser dev tools for details.
    </environment>
    <a href="" class="reload">Reload</a>
    <a class="dismiss">🗙</a>
</div>

blazor-error-uiElement jest zwykle ukryty z powodu obecności display: none stylu blazor-error-ui klasy CSS w arkuszu stylów witryny ( wwwroot/css/site.css ).The blazor-error-ui element is normally hidden due the presence of the display: none style of the blazor-error-ui CSS class in the site's stylesheet (wwwroot/css/site.css). Gdy wystąpi błąd, struktura ma zastosowanie display: block do elementu.When an error occurs, the framework applies display: block to the element.

Blazor Server Szczegóły błędów obwoduBlazor Server detailed circuit errors

Błędy po stronie klienta nie obejmują stosu wywołań i nie zawierają szczegółów przyczyny błędu, ale Dzienniki serwera zawierają takie informacje.Client-side errors don't include the call stack and don't provide detail on the cause of the error, but server logs do contain such information. W celach programistycznych informacje o błędzie obwodu poufnego mogą być udostępniane klientowi, włączając szczegółowe błędy.For development purposes, sensitive circuit error information can be made available to the client by enabling detailed errors.

Ustaw CircuitOptions.DetailedErrors wartość true .Set CircuitOptions.DetailedErrors to true. Aby uzyskać więcej informacji i zapoznać się z przykładem, zobacz Blazor SignalR Wskazówki dotyczące ASP.NET Core .For more information and an example, see Blazor SignalR Wskazówki dotyczące ASP.NET Core.

Alternatywą dla ustawienia CircuitOptions.DetailedErrors jest ustawienie DetailedErrors klucza konfiguracji true w pliku ustawień środowiska deweloperskiego aplikacji ( appsettings.Development.json ).An alternative to setting CircuitOptions.DetailedErrors is to set the DetailedErrors configuration key to true in the app's Development environment settings file (appsettings.Development.json). Ponadto należy ustawić SignalR funkcję rejestrowania po stronie serwera ( Microsoft.AspNetCore.SignalR ) w celu debugowania lub śledzenia szczegółowego SignalR rejestrowania.Additionally, set SignalR server-side logging (Microsoft.AspNetCore.SignalR) to Debug or Trace for detailed SignalR logging.

appsettings.Development.json:appsettings.Development.json:

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

DetailedErrorsKlucz konfiguracji można również ustawić true przy użyciu ASPNETCORE_DETAILEDERRORS zmiennej środowiskowej o wartości true na serwerach środowiska deweloperskiego/przejściowego lub w systemie lokalnym.The DetailedErrors configuration key can also be set to true using the ASPNETCORE_DETAILEDERRORS environment variable with a value of true on Development/Staging environment servers or on your local system.

Ostrzeżenie

Zawsze należy unikać ujawniania informacji o błędach klientom w Internecie, co stanowi zagrożenie bezpieczeństwa.Always avoid exposing error information to clients on the Internet, which is a security risk.

Jak Blazor Server Aplikacja reaguje na Nieobsłużone wyjątkiHow a Blazor Server app reacts to unhandled exceptions

Blazor Server jest strukturą stanową.Blazor Server is a stateful framework. Gdy użytkownicy współpracują z aplikacją, utrzymują połączenie z serwerem znanym jako obwód.While users interact with an app, they maintain a connection to the server known as a circuit. Obwód zawiera aktywne wystąpienia składnika, a także wiele innych aspektów stanu, takich jak:The circuit holds active component instances, plus many other aspects of state, such as:

  • Najnowsze renderowane dane wyjściowe składników.The most recent rendered output of components.
  • Bieżący zestaw delegatów obsługi zdarzeń, które mogą być wyzwalane przez zdarzenia po stronie klienta.The current set of event-handling delegates that could be triggered by client-side events.

Jeśli użytkownik otworzy aplikację na wielu kartach przeglądarki, użytkownik utworzy wiele niezależnych obwody.If a user opens the app in multiple browser tabs, the user creates multiple independent circuits.

Blazor traktuje większość nieobsłużonych wyjątków jako krytyczne dla obwodu, w którym występują.Blazor treats most unhandled exceptions as fatal to the circuit where they occur. Jeśli obwód zostanie przerwany z powodu nieobsługiwanego wyjątku, użytkownik może nadal korzystać z aplikacji tylko przez ponowne załadowanie strony w celu utworzenia nowego obwodu.If a circuit is terminated due to an unhandled exception, the user can only continue to interact with the app by reloading the page to create a new circuit. Nie ma to wpływu na obwody, które zostały przerwane, które są obwody dla innych użytkowników lub kart przeglądarki.Circuits outside of the one that's terminated, which are circuits for other users or other browser tabs, aren't affected. Ten scenariusz jest podobny do aplikacji klasycznej, która ulega awarii.This scenario is similar to a desktop app that crashes. Aplikacja, która uległa awarii, musi zostać ponownie uruchomiona, ale nie ma to wpływu na inne aplikacje.The crashed app must be restarted, but other apps aren't affected.

Struktura kończy obwód, gdy wystąpi nieobsługiwany wyjątek z następujących powodów:The framework terminates a circuit when an unhandled exception occurs for the following reasons:

  • Nieobsługiwany wyjątek często pozostawia obwód w niezdefiniowanym stanie.An unhandled exception often leaves the circuit in an undefined state.
  • Nie można zagwarantować normalnej operacji aplikacji po wystąpieniu nieobsłużonego wyjątku.The app's normal operation can't be guaranteed after an unhandled exception.
  • Luki w zabezpieczeniach mogą pojawić się w aplikacji, jeśli obwód będzie kontynuował działanie w niezdefiniowanym stanie.Security vulnerabilities may appear in the app if the circuit continues in an undefined state.

Zarządzanie nieobsługiwanymi wyjątkami w kodzie deweloperaManage unhandled exceptions in developer code

Aby aplikacja kontynuowała działanie po wystąpieniu błędu, aplikacja musi mieć logikę obsługi błędów.For an app to continue after an error, the app must have error handling logic. W dalszej części tego artykułu opisano potencjalne źródła nieobsłużonych wyjątków.Later sections of this article describe potential sources of unhandled exceptions.

W środowisku produkcyjnym nie Renderuj komunikatów wyjątków struktury ani śladów stosu w interfejsie użytkownika.In production, don't render framework exception messages or stack traces in the UI. Renderowanie komunikatów o wyjątkach lub śladów stosu może:Rendering exception messages or stack traces could:

  • Ujawnianie poufnych informacji użytkownikom końcowym.Disclose sensitive information to end users.
  • Pomóż złośliwemu użytkownikowi wykrywać słabe strony w aplikacji, która może naruszyć bezpieczeństwo aplikacji, serwera lub sieci.Help a malicious user discover weaknesses in an app that can compromise the security of the app, server, or network.

Globalna obsługa wyjątkówGlobal exception handling

Blazor jest strukturą po stronie klienta jednostronicowej aplikacji (SPA).Blazor is a single-page application (SPA) client-side framework. Przeglądarka pełni rolę hosta aplikacji i w ten sposób działa jako potok przetwarzania poszczególnych Razor składników w oparciu o żądania URI dotyczące nawigacji i zasobów statycznych.The browser serves as the app's host and thus acts as the processing pipeline for individual Razor components based on URI requests for navigation and static assets. W przeciwieństwie do ASP.NET Core aplikacji uruchamianych na serwerze z potokiem przetwarzania oprogramowania pośredniczącego, nie istnieje potok oprogramowania pośredniczącego, który przetwarza żądania dotyczące Razor składników, których można użyć do obsługi błędów globalnych.Unlike ASP.NET Core apps that run on the server with a middleware processing pipeline, there is no middleware pipeline that processes requests for Razor components that can be leveraged for global error handling. Jednak aplikacja może używać składnika przetwarzania błędów jako wartości kaskadowej do przetwarzania błędów w scentralizowany sposób.However, an app can use an error processing component as a cascading value to process errors in a centralized way.

Poniższy Error składnik przekazuje sam siebie jako CascadingValue składnik do elementów podrzędnych.The following Error component passes itself as a CascadingValue to child components. Poniższy przykład powoduje jedynie rejestrowanie błędu, ale metody składnika mogą przetwarzać błędy w dowolny sposób wymagany przez aplikację, w tym za pomocą wielu metod przetwarzania błędów.The following example merely logs the error, but methods of the component can process errors in any way required by the app, including through the use of multiple error processing methods. Zaletą korzystania z składnika przez użycie wstrzykniętej usługi lub niestandardowej implementacji rejestratora jest to, że składnik kaskadowy może renderować zawartość i stosować style CSS w przypadku wystąpienia błędu.An advantage of using a component over using an injected service or a custom logger implementation is that a cascaded component can render content and apply CSS styles when an error occurs.

Shared/Error.razor:Shared/Error.razor:

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

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

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

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

W App składniku zawiń składnik na składnik Router Error .In the App component, wrap the Router component with the Error component. Pozwala to Error składnikowi na kaskadowe umieszczanie w dowolnym składniku aplikacji, w której Error składnik został odebrany jako CascadingParameter .This permits the Error component to cascade down to any component of the app where the Error component is received as a CascadingParameter.

App.razor:App.razor:

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

Aby przetworzyć błędy w składniku:To process errors in a component:

  • Wyznacz Error składnik jako CascadingParameter w @code bloku:Designate the Error component as a CascadingParameter in the @code block:

    [CascadingParameter]
    public Error Error { get; set; }
    
  • Wywołaj metodę przetwarzania błędu w dowolnym catch bloku z odpowiednim typem wyjątku.Call an error processing method in any catch block with an appropriate exception type. Przykładowy Error składnik oferuje tylko jedną ProcessError metodę, ale składnik przetwarzania błędów może zapewnić dowolną liczbę metod przetwarzania błędów, aby rozwiązać alternatywne wymagania dotyczące przetwarzania błędów w całej aplikacji.The example Error component only offers a single ProcessError method, but the error processing component can provide any number of error processing methods to address alternative error processing requirements throughout the app.

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

Korzystając z powyższego przykładowego Error składnika i ProcessError metody, konsola narzędzi deweloperskich w przeglądarce wskazuje zarejestrowanego błędu:Using the preceding example Error component and ProcessError method, the browser's developer tools console indicates the trapped, logged error:

Niepowodzenie: Blazor Sample. Shared. Error [0] Error: ProcessError-Type: System. NullReferenceException Message: odwołanie do obiektu nie jest ustawione na wystąpienie obiektu.fail: BlazorSample.Shared.Error[0] Error:ProcessError - Type: System.NullReferenceException Message: Object reference not set to an instance of an object.

Jeśli ProcessError Metoda bezpośrednio uczestniczy w renderowaniu, na przykład wyświetlając niestandardowy pasek komunikatów o błędach lub zmieniając style CSS renderowane elementy, wywołaj StateHasChanged na końcu ProcessErrors metody, aby przetworzyć interfejs użytkownika.If the ProcessError method directly participates in rendering, such as showing a custom error message bar or changing the CSS styles of the rendered elements, call StateHasChanged at the end of the ProcessErrors method to rerender the UI.

Ponieważ metody przedstawione w tej sekcji obsługują błędy w try-catch instrukcji, SignalR połączenie między klientem i serwerem nie jest zerwane w przypadku wystąpienia błędu, a obwód pozostaje aktywny.Because the approaches in this section handle errors with a try-catch statement, the SignalR connection between the client and server isn't broken when an error occurs and the circuit remains alive. Dowolny nieobsługiwany wyjątek jest krytyczny dla obwodu.Any unhandled exception is fatal to a circuit. Aby uzyskać więcej informacji, zobacz poprzednią sekcję dotyczącą sposobu, w jaki Blazor Server Aplikacja reaguje na Nieobsłużone wyjątki.For more information, see the preceding section on how a Blazor Server app reacts to unhandled exceptions.

Rejestrowanie błędów przez dostawcę trwałegoLog errors with a persistent provider

Jeśli wystąpi nieobsługiwany wyjątek, wyjątek jest rejestrowany w ILogger wystąpieniach skonfigurowanych w kontenerze usługi.If an unhandled exception occurs, the exception is logged to ILogger instances configured in the service container. Domyślnie Blazor aplikacje rejestrują dane wyjściowe konsoli z dostawcą rejestrowania konsoli.By default, Blazor apps log to console output with the Console Logging Provider. Należy rozważyć rejestrowanie do bardziej trwałej lokalizacji na serwerze z dostawcą, który zarządza rozmiarem dziennika i rotacją dzienników.Consider logging to a more permanent location on the server with a provider that manages log size and log rotation. Alternatywnie aplikacja może używać usługi zarządzania wydajnością aplikacji (APM), takiej jak Azure Application Insights (Azure monitor).Alternatively, the app can use an Application Performance Management (APM) service, such as Azure Application Insights (Azure Monitor).

Podczas opracowywania Blazor Server aplikacja zwykle wysyła pełne szczegóły wyjątków do konsoli przeglądarki w celu ułatwienia debugowania.During development, a Blazor Server app usually sends the full details of exceptions to the browser's console to aid in debugging. W środowisku produkcyjnym szczegółowe błędy nie są wysyłane do klientów, ale na serwerze są rejestrowane pełne szczegóły wyjątku.In production, detailed errors aren't sent to clients, but an exception's full details are logged on the server.

Należy zdecydować, które zdarzenia mają być rejestrowane, oraz poziom ważności zarejestrowanych zdarzeń.You must decide which incidents to log and the level of severity of logged incidents. Nieszkodliwi użytkownicy mogą być w stanie wyzwolić błędy w sposób celowy.Hostile users might be able to trigger errors deliberately. Na przykład nie należy rejestrować zdarzenia z błędu, gdy ProductId w adresie URL składnika, który zawiera szczegółowe informacje o produkcie.For example, don't log an incident from an error where an unknown ProductId is supplied in the URL of a component that displays product details. Nie wszystkie błędy powinny być traktowane jako zdarzenia do rejestrowania.Not all errors should be treated as incidents for logging.

Aby uzyskać więcej informacji, zobacz następujące artykuły:For more information, see the following articles:

†Dotyczy aplikacji ASP.NET Core po stronie serwera, które są aplikacjami zaplecza interfejsu API sieci Web dla Blazor aplikacji.†Applies to server-side ASP.NET Core apps that are web API backend apps for Blazor apps.

Miejsca, w których mogą wystąpić błędyPlaces where errors may occur

Kod struktury i aplikacji może wyzwolić Nieobsłużone wyjątki w następujących lokalizacjach, które opisano w następujących sekcjach tego artykułu:Framework and app code may trigger unhandled exceptions in any of the following locations, which are described further in the following sections of this article:

Tworzenie wystąpienia składnikaComponent instantiation

Podczas Blazor tworzenia wystąpienia składnika:When Blazor creates an instance of a component:

  • Konstruktor składnika jest wywoływany.The component's constructor is invoked.
  • Konstruktory wszelkich niepojedynczych usług DI dostarczonych do konstruktora składnika za pośrednictwem @inject dyrektywy lub [Inject] atrybutu są wywoływane.The constructors of any non-singleton DI services supplied to the component's constructor via the @inject directive or the [Inject] attribute are invoked.

Blazor ServerObwód kończy się niepowodzeniem, gdy dowolny wykonany Konstruktor lub setter dla każdej [Inject] właściwości zgłasza nieobsługiwany wyjątek.A Blazor Server circuit fails when any executed constructor or a setter for any [Inject] property throws an unhandled exception. Wyjątek jest krytyczny, ponieważ struktura nie może utworzyć wystąpienia składnika.The exception is fatal because the framework can't instantiate the component. Jeśli logika konstruktora może generować wyjątki, aplikacja powinna zalewkować wyjątki przy użyciu try-catch instrukcji z obsługą błędów i rejestrowaniem.If constructor logic may throw exceptions, the app should trap the exceptions using a try-catch statement with error handling and logging.

Metody cyklu życiaLifecycle methods

W okresie istnienia składnika Blazor wywołuje metody cyklu życia.During the lifetime of a component, Blazor invokes lifecycle methods. Jeśli jakakolwiek metoda cyklu życia zgłasza wyjątek, synchronicznie lub asynchronicznie, wyjątek jest krytyczny dla Blazor Server obwodu.If any lifecycle method throws an exception, synchronously or asynchronously, the exception is fatal to a Blazor Server circuit. Aby składniki zajmowały błędy w metodach cyklu życia, Dodaj logikę obsługi błędów.For components to deal with errors in lifecycle methods, add error handling logic.

W poniższym przykładzie, gdzie OnParametersSetAsync wywołuje metodę w celu uzyskania produktu:In the following example where OnParametersSetAsync calls a method to obtain a product:

  • Wyjątek zgłoszony w ProductRepository.GetProductByIdAsync metodzie jest obsługiwany przez try-catch instrukcję.An exception thrown in the ProductRepository.GetProductByIdAsync method is handled by a try-catch statement.
  • Gdy catch blok jest wykonywany:When the catch block is executed:
    • loadFailed jest ustawiona na true , która jest używana do wyświetlania komunikatu o błędzie dla użytkownika.loadFailed is set to true, which is used to display an error message to the user.
    • Błąd jest rejestrowany.The error is logged.
@page "/product-details/{ProductId:int}"
@using Microsoft.Extensions.Logging
@inject IProductRepository ProductRepository
@inject ILogger<ProductDetails> Logger

@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;
            details = await ProductRepository.GetProductByIdAsync(ProductId);
        }
        catch (Exception ex)
        {
            loadFailed = true;
            Logger.LogWarning(ex, "Failed to load product {ProductId}", ProductId);
        }
    }
}
@page "/product-details/{ProductId:int}"
@using Microsoft.Extensions.Logging
@inject IProductRepository ProductRepository
@inject ILogger<ProductDetails> Logger

@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;
            details = await ProductRepository.GetProductByIdAsync(ProductId);
        }
        catch (Exception ex)
        {
            loadFailed = true;
            Logger.LogWarning(ex, "Failed to load product {ProductId}", ProductId);
        }
    }
}

Logika renderowaniaRendering logic

Znaczniki deklaratywne w Razor pliku składnika ( .razor ) są kompilowane do metody języka C# o nazwie BuildRenderTree .The declarative markup in a Razor component file (.razor) is compiled into a C# method called BuildRenderTree. Gdy składnik renderuje, BuildRenderTree wykonuje i tworzy strukturę danych opisującą elementy, tekst i składniki podrzędne renderowanego składnika.When a component renders, BuildRenderTree executes and builds up a data structure describing the elements, text, and child components of the rendered component.

Logika renderowania może zgłosić wyjątek.Rendering logic can throw an exception. Przykład tego scenariusza występuje, gdy @someObject.PropertyName jest oceniane, ale @someObject jest null .An example of this scenario occurs when @someObject.PropertyName is evaluated but @someObject is null. Nieobsługiwany wyjątek zgłoszony przez logikę renderowania jest krytyczny dla Blazor Server obwodu.An unhandled exception thrown by rendering logic is fatal to a Blazor Server circuit.

Aby uniknąć NullReferenceException renderowania logiki, null przed uzyskaniem dostępu do elementów członkowskich Sprawdź, czy jest on obiektem.To prevent a NullReferenceException in rendering logic, check for a null object before accessing its members. W poniższym przykładzie person.Address właściwości nie są dostępne, jeśli person.Address null :In the following example, person.Address properties aren't accessed if 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>
}
@if (person.Address != null)
{
    <div>@person.Address.Line1</div>
    <div>@person.Address.Line2</div>
    <div>@person.Address.City</div>
    <div>@person.Address.Country</div>
}

Poprzedni kod założono, że person nie jest null .The preceding code assumes that person isn't null. Często Struktura kodu gwarantuje, że obiekt istnieje w momencie renderowania składnika.Often, the structure of the code guarantees that an object exists at the time the component is rendered. W takich przypadkach nie jest konieczne sprawdzanie null logiki renderowania.In those cases, it isn't necessary to check for null in rendering logic. W poprzednim przykładzie person można zagwarantować, że istnieje, ponieważ person jest tworzony podczas tworzenia wystąpienia składnika, jak pokazano na poniższym przykładzie:In the prior example, person might be guaranteed to exist because person is created when the component is instantiated, as the following example shows:

@code {
    private Person person = new();

    ...
}
@code {
    private Person person = new Person();

    ...
}

Procedury obsługi zdarzeńEvent handlers

Kod po stronie klienta wyzwala wywołania kodu C#, gdy programy obsługi zdarzeń są tworzone przy użyciu:Client-side code triggers invocations of C# code when event handlers are created using:

  • @onclick
  • @onchange
  • Inne @on... atrybutyOther @on... attributes
  • @bind

Kod procedury obsługi zdarzeń może zgłosić nieobsługiwany wyjątek w tych scenariuszach.Event handler code might throw an unhandled exception in these scenarios.

Jeśli procedura obsługi zdarzeń zgłasza nieobsługiwany wyjątek (na przykład kwerenda bazy danych kończy się niepowodzeniem), wyjątek jest krytyczny dla Blazor Server obwodu.If an event handler throws an unhandled exception (for example, a database query fails), the exception is fatal to a Blazor Server circuit. Jeśli aplikacja wywołuje kod, który może zakończyć się niepowodzeniem z powodów zewnętrznych, należy zastosować wyjątek pułapki przy użyciu try-catch instrukcji z obsługą błędów i rejestrowaniem.If the app calls code that could fail for external reasons, trap exceptions using a try-catch statement with error handling and logging.

Jeśli kod użytkownika nie jest pułapk i nie obsługuje wyjątku, struktura rejestruje wyjątek i kończy obwód.If user code doesn't trap and handle the exception, the framework logs the exception and terminates the circuit.

Usuwanie składnikówComponent disposal

Składnik może zostać usunięty z interfejsu użytkownika, na przykład, ponieważ użytkownik przeszedł do innej strony.A component may be removed from the UI, for example, because the user has navigated to another page. Gdy składnik implementujący System.IDisposable jest usuwany z interfejsu użytkownika, struktura wywołuje Dispose metodę składnika.When a component that implements System.IDisposable is removed from the UI, the framework calls the component's Dispose method.

Jeśli Dispose Metoda składnika zgłasza nieobsługiwany wyjątek, wyjątek jest krytyczny dla Blazor Server obwodu.If the component's Dispose method throws an unhandled exception, the exception is fatal to a Blazor Server circuit. Jeśli logika usuwania może generować wyjątki, aplikacja powinna zalewkować wyjątki przy użyciu try-catch instrukcji z obsługą błędów i rejestrowaniem.If disposal logic may throw exceptions, the app should trap the exceptions using a try-catch statement with error handling and logging.

Aby uzyskać więcej informacji na temat usuwania składników, zobacz ASP.NET Podstawowy Razor cykl życia składnika .For more information on component disposal, see ASP.NET Podstawowy Razor cykl życia składnika.

Międzyoperacyjność w języku JavaScriptJavaScript interop

IJSRuntime.InvokeAsync umożliwia programowi .NET Code wykonywanie wywołań asynchronicznych do środowiska uruchomieniowego JavaScript w przeglądarce użytkownika.IJSRuntime.InvokeAsync allows .NET code to make asynchronous calls to the JavaScript runtime in the user's browser.

Poniższe warunki dotyczą obsługi błędów w programie InvokeAsync :The following conditions apply to error handling with InvokeAsync:

  • Jeśli wywołanie InvokeAsync synchronicznie zakończy się niepowodzeniem, wystąpi wyjątek programu .NET.If a call to InvokeAsync fails synchronously, a .NET exception occurs. Wywołanie InvokeAsync może zakończyć się niepowodzeniem, na przykład dlatego, że nie można serializować dostarczonych argumentów.A call to InvokeAsync may fail, for example, because the supplied arguments can't be serialized. Kod dewelopera musi przechwycić wyjątek.Developer code must catch the exception. Jeśli kod aplikacji w obsłudze zdarzeń lub metoda cyklu życia składnika nie obsługuje wyjątku, wynikający z nich wyjątek jest krytyczny dla Blazor Server obwodu.If app code in an event handler or component lifecycle method doesn't handle an exception, the resulting exception is fatal to a Blazor Server circuit.
  • Jeśli wywołanie InvokeAsync powiedzie się asynchronicznie, .NET Task kończy się niepowodzeniem.If a call to InvokeAsync fails asynchronously, the .NET Task fails. Wywołanie InvokeAsync może zakończyć się niepowodzeniem, na przykład ponieważ kod po stronie JavaScript zgłasza wyjątek lub zwraca Promise , który został ukończony jako rejected .A call to InvokeAsync may fail, for example, because the JavaScript-side code throws an exception or returns a Promise that completed as rejected. Kod dewelopera musi przechwycić wyjątek.Developer code must catch the exception. W przypadku użycia await operatora Rozważ zapakowanie wywołania metody w try-catch instrukcji z obsługą błędów i rejestrowaniem.If using the await operator, consider wrapping the method call in a try-catch statement with error handling and logging. W przeciwnym razie niepowodzenie kodu spowoduje nieobsłużony wyjątek, który jest krytyczny dla Blazor Server obwodu.Otherwise, the failing code results in an unhandled exception that's fatal to a Blazor Server circuit.
  • Domyślnie wywołania programu InvokeAsync muszą zakończyć się w określonym przedziale czasu lub w przeciwnym razie upłynął limit czasu połączenia. Domyślny limit czasu wynosi jedną minutę.By default, calls to InvokeAsync must complete within a certain period or else the call times out. The default timeout period is one minute. Limit czasu chroni kod przed utratą połączenia sieciowego lub kodem JavaScript, który nigdy nie odsyła komunikat uzupełniający.The timeout protects the code against a loss in network connectivity or JavaScript code that never sends back a completion message. Jeśli wystąpiło przełączenie, wynikiem System.Threading.Tasks kończy się niepowodzeniem a OperationCanceledException .If the call times out, the resulting System.Threading.Tasks fails with an OperationCanceledException. Zalewka i przetwórz wyjątek z rejestrowaniem.Trap and process the exception with logging.

Podobnie kod JavaScript może inicjować wywołania metod .NET wskazywanych przez [JSInvokable] atrybut.Similarly, JavaScript code may initiate calls to .NET methods indicated by the [JSInvokable] attribute. Jeśli te metody .NET zgłaszają nieobsługiwany wyjątek:If these .NET methods throw an unhandled exception:

  • Wyjątek nie jest traktowany jako krytyczny dla Blazor Server obwodu.The exception isn't treated as fatal to a Blazor Server circuit.
  • Po stronie JavaScript Promise jest odrzucany.The JavaScript-side Promise is rejected.

Istnieje możliwość użycia kodu obsługi błędów po stronie .NET lub stronie JavaScript wywołania metody.You have the option of using error handling code on either the .NET side or the JavaScript side of the method call.

Aby uzyskać więcej informacji, zobacz następujące artykuły:For more information, see the following articles:

Blazor Server Renderowanie prerenderinguBlazor Server prerendering

Blazor składniki mogą być wstępnie renderowane przy użyciu pomocnika tagów składnika , dzięki czemu RENDEROWANE znaczniki HTML są zwracane jako część początkowego żądania HTTP użytkownika.Blazor components can be prerendered using the Component Tag Helper so that their rendered HTML markup is returned as part of the user's initial HTTP request. Działa to w następujący sposób:This works by:

  • Tworzenie nowego obwodu dla wszystkich wstępnie renderowanych składników, które są częścią tej samej strony.Creating a new circuit for all of the prerendered components that are part of the same page.
  • Generowanie początkowego kodu HTML.Generating the initial HTML.
  • Przetraktowanie obwodu disconnected do momentu, aż przeglądarka użytkownika nawiąże SignalR połączenie z powrotem z tym samym serwerem.Treating the circuit as disconnected until the user's browser establishes a SignalR connection back to the same server. Po nawiązaniu połączenia zostanie wznowione działanie międzydziałające w obwodzie i zostanie zaktualizowane oznaczenie HTML składników.When the connection is established, interactivity on the circuit is resumed and the components' HTML markup is updated.

Jeśli jakikolwiek składnik zgłasza nieobsłużony wyjątek podczas renderowania pre, na przykład podczas wykonywania metody cyklu życia lub logiki renderowania:If any component throws an unhandled exception during prerendering, for example, during a lifecycle method or in rendering logic:

  • Wyjątek jest krytyczny dla obwodu.The exception is fatal to the circuit.
  • Wyjątek jest generowany w stosie wywołań z ComponentTagHelper pomocnika tagów.The exception is thrown up the call stack from the ComponentTagHelper Tag Helper. W związku z tym całe żądanie HTTP kończy się niepowodzeniem, chyba że wyjątek jest jawnie przechwycony przez kod dewelopera.Therefore, the entire HTTP request fails unless the exception is explicitly caught by developer code.

W normalnych warunkach w przypadku niepowodzenia wstępnego renderowania kontynuowanie kompilowania i renderowania składnika nie ma sensu, ponieważ nie można renderować składnika roboczego.Under normal circumstances when prerendering fails, continuing to build and render the component doesn't make sense because a working component can't be rendered.

Aby tolerować błędy, które mogą wystąpić podczas renderowania prerenderingu, logika obsługi błędów musi być umieszczona wewnątrz składnika, który może zgłaszać wyjątki.To tolerate errors that may occur during prerendering, error handling logic must be placed inside a component that may throw exceptions. Używaj try-catch instrukcji z obsługą błędów i rejestrowaniem.Use try-catch statements with error handling and logging. Zamiast zawijać ComponentTagHelper pomocnika tagów w try-catch instrukcji, umieść logikę obsługi błędów w składniku renderowanym przez ComponentTagHelper pomocnika tagów.Instead of wrapping the ComponentTagHelper Tag Helper in a try-catch statement, place error handling logic in the component rendered by the ComponentTagHelper Tag Helper.

Scenariusze zaawansowaneAdvanced scenarios

Renderowanie cykliczneRecursive rendering

Składniki można cyklicznie zagnieżdżać.Components can be nested recursively. Jest to przydatne do reprezentowania struktur danych rekursywnych.This is useful for representing recursive data structures. Na przykład TreeNode składnik może renderować więcej TreeNode składników dla każdego węzła podrzędnego.For example, a TreeNode component can render more TreeNode components for each of the node's children.

W przypadku renderowania cyklicznego należy unikać tworzenia wzorców, które powodują nieskończoną rekursję:When rendering recursively, avoid coding patterns that result in infinite recursion:

  • Nie Renderuj rekursywnie struktury danych zawierającej cykl.Don't recursively render a data structure that contains a cycle. Na przykład nie Renderuj węzła drzewa, którego elementy podrzędne zawierają sam siebie.For example, don't render a tree node whose children includes itself.
  • Nie twórz łańcucha układów zawierających cykl.Don't create a chain of layouts that contain a cycle. Na przykład nie twórz układu, którego układ jest sam.For example, don't create a layout whose layout is itself.
  • Nie Zezwalaj użytkownikowi końcowemu na naruszenie nieodmian rekursji (reguł) przy użyciu złośliwego wpisu danych lub wywołań międzyoperacyjnych języka JavaScript.Don't allow an end user to violate recursion invariants (rules) through malicious data entry or JavaScript interop calls.

Nieskończone pętle podczas renderowania:Infinite loops during rendering:

  • Powoduje, że proces renderowania kontynuuje działanie zawsze.Causes the rendering process to continue forever.
  • Jest równoznaczny z tworzeniem niezakończonej pętli.Is equivalent to creating an unterminated loop.

W tych scenariuszach obwód, którego to dotyczy, Blazor Server kończy się niepowodzeniem, a wątek zwykle próbuje wykonać:In these scenarios, an affected Blazor Server circuit fails, and the thread usually attempts to:

  • Zużywaj ilość czasu procesora CPU dozwoloną przez system operacyjny w nieskończoność.Consume as much CPU time as permitted by the operating system, indefinitely.
  • Korzystaj z nieograniczonej ilości pamięci serwera.Consume an unlimited amount of server memory. Zużywanie nieograniczonej pamięci jest równoważne scenariuszowi, w którym niezakończona pętla dodaje wpisy do kolekcji na każdej iteracji.Consuming unlimited memory is equivalent to the scenario where an unterminated loop adds entries to a collection on every iteration.

Aby uniknąć nieskończonych wzorców rekursji, należy się upewnić, że kod renderowania cyklicznego zawiera odpowiednie warunki zatrzymania.To avoid infinite recursion patterns, ensure that recursive rendering code contains suitable stopping conditions.

Logika drzewa renderowania niestandardowegoCustom render tree logic

Większość Blazor składników jest implementowana jako Razor pliki składników ( .razor ) i są kompilowane przez platformę w celu utworzenia logiki, która działa w RenderTreeBuilder celu renderowania danych wyjściowych.Most Blazor components are implemented as Razor component files (.razor) and are compiled by the framework to produce logic that operates on a RenderTreeBuilder to render their output. Jednak deweloper może ręcznie zaimplementować RenderTreeBuilder logikę przy użyciu procedury kodu w języku C#.However, a developer may manually implement RenderTreeBuilder logic using procedural C# code. Aby uzyskać więcej informacji, zobacz BlazorZaawansowane scenariusze ASP.NET Core.For more information, see BlazorZaawansowane scenariusze ASP.NET Core.

Ostrzeżenie

Korzystanie z logiki konstruktora drzewa renderowania ręcznego jest uznawane za zaawansowane i niebezpieczne scenariusze, które nie są zalecane do ogólnego tworzenia składników.Use of manual render tree builder logic is considered an advanced and unsafe scenario, not recommended for general component development.

Jeśli RenderTreeBuilder kod zostanie zapisany, Deweloper musi zagwarantować poprawność kodu.If RenderTreeBuilder code is written, the developer must guarantee the correctness of the code. Na przykład Deweloper musi upewnić się, że:For example, the developer must ensure that:

  • Wywołania OpenElement i CloseElement są prawidłowo zrównoważone.Calls to OpenElement and CloseElement are correctly balanced.
  • Atrybuty są dodawane tylko w prawidłowych miejscach.Attributes are only added in the correct places.

Nieprawidłowa ręczna logika konstruktora drzewa renderowania może spowodować dowolne niezdefiniowane zachowanie, w tym awarie, zawieszenie serwera i luki w zabezpieczeniach.Incorrect manual render tree builder logic can cause arbitrary undefined behavior, including crashes, server hangs, and security vulnerabilities.

Rozważ ręczne renderowanie logiki konstruktora drzew drzewa na tym samym poziomie złożoności i z tym samym poziomem zagrożenia co ręczne pisanie kodu zestawu lub języka pośredniego firmy Microsoft (MSIL) .Consider manual render tree builder logic on the same level of complexity and with the same level of danger as writing assembly code or Microsoft Intermediate Language (MSIL) instructions by hand.

Dodatkowe zasobyAdditional resources

†Dotyczy aplikacji ASP.NET Core po stronie serwera, które są aplikacjami zaplecza interfejsu API sieci Web dla Blazor aplikacji.†Applies to server-side ASP.NET Core apps that are web API backend apps for Blazor apps.