Unhandled exception rendering from



Очень нужна помощь, макс вылетает из-за ошибки Врай.

Если почеловечнее, то вылетает при подготовке (препарации) менеджера света.

Скорее всего не хватает сил обсчитать все светильники. А может они глюкнули.
СТоит попробывать убрать часть, а может удалить все источники и выставить их заново

а решения проблем с нехваткой памяти вирай описаны очень подробно ниже:

если методы изложенные тут не помогут (то есть картинку желаем больше чем 3000х3000 пикселей) то 100% все будет решено по нижеследующей методике:

Vikysik
даже вообще без света что ли?

вообще макс вылетает чаще всего по:
— если в материале нажали кнопку видимости текстуры на основном меню (на заходя в меню настройки самой текстуры)
— если в сцене неправильная геометрия создает всякие траблы ))) это бывает когда импортируешь чужие модели
— но чаще всего — это недостаток памяти компьютера.

ps — я тебе в личку скину ссылки на шоп, сегодня 1 из 4, остальное завтра

Искал решение проблемы с данной ошибкой.
Error: UNHANDLED EXCEPTION: Rendering frame last marker is at./src/ vray render cpp. line 2194reparing global light manager.

У меня вылетал Макс на батч рендере. Постоянно. Ресурс компьютера нормльный для данной сцены. 2012 Макс + V-ray 2.20. Винда 64 битная. В общем решается проблема очень просто. Это все из-за матов с которыми не дружит вирей. Стандартные маты которые кто-то все таки использует при моделировании.
Устраняется все очень просто. В любой проекции тыкаете правой кнопкой мыши и выбирате Vray Scene Converter. Ну и там просто жмете ок везде и все стандартные маты автоматом переконвертируются в Vray. И все. Проблема исчезла.

Источник

Unhandled exception rendering component: Microsoft.JSInterop.JSException: Cannot read property ‘ownerDocument’ of null #19647

Comments

AlexCorona55 commented Mar 6, 2020 •

Describe the bug

Hello, im pretty new with Blazor WASM. Also this is my first github issue, so if there is a problem with the description, please let me know to fix it and improve 🙂

I’ve an inconsistent exception when rendering a component with two @page annotations:

@page «/partnerForm»
@page «/partnerForm/»
@Attribute [Authorize]
@using Microsoft.AspNetCore.Authorization

The first one causes the exception listened below when the navigation occures (actually, the OnInitializedAsync event exectues fine, but the exception occures whith the rendering).
Also, when i refresh, the flow is normal, no exceptios, no errors, no warnings.

The second one does not cause any problem at all.

To Reproduce

The navigations is like this from another component:

  1. NavigationManager.NavigateTo(«partnerForm»); (this causes the exception)
  2. NavigationManager.NavigateTo($»partnerForm/«); (this works fine).

Exception:

Further technical details

  • ASP.NET Core version 3.1.1
  • Blazor 3.2 preview1.20073.1
  • The IDE is VS 16.4.5

The text was updated successfully, but these errors were encountered:

Источник

Work With Unhandled Exceptions Gracefully in Blazor Server With .NET 6 Error Boundaries

Let’s look at error boundaries in Blazor, a new feature that allows you to handle Blazor Server unhandled exceptions more easily. We’ll learn what error boundaries are, and what they are not.

In Blazor—especially Blazor Server—there is no such thing as a small unhandled exception. When Blazor Server detects an unhandled exception from a component, ASP.NET Core treats it as a fatal exception. Why?

Blazor Server apps implement data processing statefully so that the client and server can have a “long-lived relationship.” To accomplish this, Blazor Server creates a circuit server-side, which indicates to the browser how to respond to events and what to render. When an unhandled exception occurs, Blazor Server treats it as a fatal error because the circuit hangs in an undefined state, which can potentially lead to usability or security problems.

As a result, your app is as good as dead, it loses its state, and your users are met with an undesirable An unhandled error has occurred message, with a link to reload the page.

In many cases, unhandled exceptions can be out of a developer’s control—like when you have an issue with third-party code. From a practical perspective, it’s not realistic to assume components will never throw an error.

Here’s an example that a Blazor developer posted on GitHub. Let’s say I’ve got two components: MyNicelyWrittenComponent , which I wrote, and a third-party component, BadlyWrittenComponent , which I did not write. (Badly written components rarely identify themselves so well, but I digress.)

What if the third-party code is coded like this?

While I can reasonably expect BadlyWrittenComponent to blow up, the circuit is broken, and I can’t salvage MyNicelyWrittenComponent . This begs the question: If I get an unhandled exception from a single component, why should my entire app die?

As a Blazor developer, you’re left spending a lot of time hacking around this by putting try and catch blocks around every single method of your app, leading to performance issues—especially with cascading parameters.

If you look at our front-end ecosystems, like React, they use error boundaries to catch errors in a component tree and display a fallback UI when a failure occurs for a single component. When this happens, the errors are isolated to the problematic component, and the rest of the application remains functional.

Fear no more: With .NET 6 Preview 4, the ASP.NET Core team introduced Blazor error boundaries. Inspired by error boundaries in React, the errorBoundary component attempts to catch recoverable errors that can’t permanently corrupt state—and like the React feature, it also renders a fallback UI.

From the error boundaries design document, the team notes that its primary goals are to allow developers to provide fallback UIs for component subtrees if an exception exists, to allow developers to provide cleaner fallback experiences and to provide more fine-grained control over how to handle failures. This capability won’t catch all possible exceptions but most common scenarios such as the various lifecycle methods (like OnInitializedAsync , OnParametersSetAsync and OnAfterRenderAsync ) and rendering use cases with BuildRenderTree .

In this post, I’ll help you understand what error boundaries are—and, just as importantly, what they aren’t.

What’s New in .NET 6 for Blazor?

.NET 6 is coming and, with it, some notable Blazor improvements . Dynamic components, hot reload, Blazor MAUI apps—the list goes on and on.

Get Started: Add Error Boundaries to the Main Layout

To get started, let’s use a quick example. Let’s say I know a guy—let’s call him MAUI Man—who runs a surf shop. In this case, MAUI Man has a Blazor Server app where he sells surfboards and T-shirts. His developer, Ed, wrote a ProductService that retrieves this data.

Let’s say the Surfboard API is having problems. Before the error boundary functionality was introduced, my component would fail to process the unhandled exception, and I’d see the typical error message at the bottom of the page.

Let’s use the new ErrorBoundary component instead. To do this, navigate to the MainLayout.razor file. (If you aren’t familiar, the MainLayout component is your Blazor app’s default layout.)

In this file, surround the @Body declaration with the ErrorBoundary component. If an unhandled exception is thrown, we’ll render a fallback error UI.

On the home page where we call the Surfboard API, we see the default error UI.

The default UI does not include any content other than An error has occurred. Even in development scenarios, you won’t see stack trace information. Later in this post, I’ll show you how you can include it.

This UI renders an empty

In this example, I include the @Body inside a RenderFragment called ChildContent . This content displays when no error occurs. Inside ErrorContent —which, for the record, is technically a RenderFragment —displays when there’s an unhandled error.

How else can you work with the ErrorBoundary ? Let’s explore.

Exploring the ErrorBoundary Component

Aside from the ChildContent and ErrorContent fragments, the out-of-the-box ErrorBoundary component also provides a CurrentException property—it’s an Exception type you can use to get stack trace information. You can use this to add to your default error message (which should only be exposed in development environments for security reasons).

Most importantly, the ErrorBoundary component allows you to call a Recover method, which resets the error boundary to a “non-errored state.” By default, the component handles up to 100 errors through its MaximumErrorCount property.

The Recover method does three things for you: It resets the component’s error count to 0 , clears the CurrentException and calls StateHasChanged . The StateHasChanged call notifies components that the state has changed and typically causes your component to be rerendered.

We can use this to browse to our Shirts component when we have an issue with the Surfboard API (or the other way around). Since the boundary is set in the main layout, at first we see the default error UI on every page. We can use the component’s Recover method to reset the error boundaries on subsequent page navigations.

As a best practice, you’ll typically want to define your error boundaries at a more granular level. Armed with some knowledge about how the ErrorBoundary component works, let’s do just that.

Dealing with Bad Data

It’s quite common to experience issues with getting and fetching data, whether it’s from a database directly or from APIs we’re calling (either internal or external APIs). This can happen for a variety of reasons—from a flaky connection, an API’s breaking changes or just inconsistent data.

In my ShirtList component, we call off to a ShirtService . Here’s what I have in ShirtList.razor.cs :

In my ShirtList.razor file, I’m iterating through the ShirtProductsList and displaying it. (If you’ve worked in ASP.NET Core before, you’ve done this anywhere between five million and ten million times.)

Instead, I can wrap the display in an ErrorBoundary and catch the error to display a message instead. (In this example, to avoid repetition, I’ll show the

section for the Razor component.)

In this situation, the ErrorBoundary can take a @key , which in my case is the individual Surfboard , which lives in the board variable. The ChildContent will display the data just as before, assuming I don’t get any errors.

If I encounter any unhandled errors, I’ll use ErrorContent to define the contents of the error message. In my case, it provides a more elegant solution than placing generic try and catch statements all over the place.

What Error Boundaries Aren’t

I hope this gentle introduction to Blazor error boundaries has helped you understand how it all works. We should also talk about which use cases aren’t a great fit for error boundaries.

Blazor error boundaries are not meant to be a global exception handling mechanism for any and all unhandled errors you encounter in your apps. You should be able to log all uncaught exceptions using the ILogger interface.

While you can mark all your components with error boundaries and ignore exceptions, you should take a more nuanced approach to your application’s error handling. Error boundaries are meant for control over your specific component’s unhandled exceptions and not as a quick way to manage failures throughout your entire application.

Conclusion

While it’s been nice to see the growth of Blazor over the several years, it’s also great to see how the ASP.NET Core team isn’t afraid to add new features by looking around at other leading front-end libraries—for example, the CSS isolation was inspired by Vue and error boundaries are taking cues from what React has done. Not only is Blazor built on open web technologies, but it’s also not afraid to look around the community to make things better.

Do you find this useful? Will it help you manage component-specific unhandled exceptions? Let us know in the comments.

Источник

Обработка ошибок в приложениях ASP.NET Core Blazor

В этой статье описывается, как Blazor управляет необработанными исключениями и как разрабатывать приложения, которые обнаруживают и обрабатывают ошибки.

Подробные сведения об ошибках во время разработки

Если во время разработки приложение Blazor работает неправильно, подробные сведения об ошибках в приложении могут помочь в устранении неполадок. При возникновении ошибки в приложении Blazor в нижней части экрана отображается светло-желтая полоса:

  • Во время разработки из этой полосы можно перейти в консоль браузера, где можно просмотреть исключение.
  • В рабочей среде эта полоса уведомляет пользователя о том, что произошла ошибка, и рекомендует обновить содержимое окна браузера.

Пользовательский интерфейс для этого процесса обработки ошибок входит в состав шаблонов проектов Blazor.

В приложении Blazor Server настройте интерфейс в файле Pages/_Host.cshtml :

В приложении Blazor WebAssembly настройте интерфейс в файле wwwroot/index.html :

Элемент blazor-error-ui обычно скрыт из-за наличия стиля display: none класса CSS blazor-error-ui в таблице стилей сайта ( wwwroot/css/site.css для Blazor Server или wwwroot/css/app.css для Blazor WebAssembly). При возникновении ошибки платформа применяет display: block к элементу.

Подробное описание ошибок каналов

Этот раздел относится к приложениям Blazor Server.

Ошибки на стороне клиента не включают сведения о стеке вызовов и не предоставляют сведения о причине ошибки, но журналы сервера содержат эти сведения. В целях разработки конфиденциальные сведения об ошибках каналов можно сделать доступными для клиента, включив подробное описание ошибок.

Задайте для параметра CircuitOptions.DetailedErrors значение true . Дополнительные сведения и пример см. в разделе Руководство поBlazorSignalR ASP.NET Core .

В качестве альтернативы заданию параметра CircuitOptions.DetailedErrors можно задать для ключа конфигурации DetailedErrors значение true в файле параметров окружения разработки приложения ( appsettings.Development.json ). Кроме того, задайте для параметра SignalRведения журнала на стороне сервера ( Microsoft.AspNetCore.SignalR ) значение Отладка или Трассировка, чтобы обеспечить подробное ведение журнала SignalR.

Можно также задать DetailedErrors значение true для ключа конфигурации, используя переменную окружения ASPNETCORE_DETAILEDERRORS со значением true на серверах окружения разработки и промежуточной среды или в локальной системе.

Никогда не предоставляйте сведения об ошибках клиентам в Интернете, так как это подвергает безопасность угрозе.

Управление необработанными исключениями в коде разработчика

Чтобы приложение продолжало работу после возникновения ошибки, в нем должна быть логика обработки ошибок. В последующих разделах этой статьи описываются потенциальные источники необработанных исключений.

В рабочей среде не следует отображать сообщения об исключениях платформы или трассировки стека в пользовательском интерфейсе. Отображение сообщений об исключениях или трассировок стека может:

  • Раскрыть конфиденциальные сведения конечным пользователям.
  • Помочь злоумышленнику обнаружить слабые места в приложении, что может нарушить безопасность приложения, сервера или сети.

Blazor Server необработанные исключения

Этот раздел относится к приложениям Blazor Server.

Blazor Server — это платформа с отслеживанием состояния. Когда пользователи взаимодействуют с приложением, они поддерживают подключение к серверу, которое называется каналом. Канал содержит экземпляры активных компонентов, а также многие другие аспекты состояния, например:

  • Последние отображаемые выходные данные компонентов.
  • Текущий набор делегатов обработки событий, которые могут вызываться событиями на стороне клиента.

Если пользователь открывает приложение на нескольких вкладках браузера, он создает несколько независимых каналов.

Blazor обрабатывает большинство необработанных исключений как неустранимые для канала, где они происходят. Если канал завершается из-за необработанного исключения, пользователь может продолжить взаимодействие с приложением только путем перезагрузки страницы для создания нового канала. Это не влияет на остальные каналы для других пользователей или других вкладок браузера. Этот сценарий аналогичен сценарию с настольным приложением, которое аварийно завершает работу. Такое приложение необходимо перезапустить, но остальные приложения это не затрагивает.

Платформа завершает канал при возникновении необработанного исключения по следующим причинам:

  • Необработанное исключение часто оставляет канал в неопределенном состоянии.
  • После необработанного исключения нормальную работу приложения невозможно гарантировать.
  • Дальнейшая работа канала в неопределенном состоянии может стать причиной уязвимостей системы безопасности.

Границы ошибок

Blazor — это клиентская платформа одностраничного приложения (SPA). Браузер служит узлом приложения и, таким образом, действует как конвейер обработки для отдельных компонентов Razor на основе запросов URI для навигации и статических ресурсов. В отличие от приложений ASP.NET Core, которые работают на сервере с конвейером обработки ПО промежуточного слоя, конвейера ПО промежуточного слоя, обрабатывающего запросы компонентов Razor, которые можно использовать для глобальной обработки ошибок, не существует. Однако в качестве каскадного значения для централизованной обработки ошибок приложение может использовать компонент обработки ошибок.

Границы ошибок предоставляют удобный подход к обработке исключений. Компонент ErrorBoundary:

  • Отображает свое дочернее содержимое при возникновении ошибки.
  • Отображает пользовательский интерфейс ошибки при возникновении необработанного исключения.

Чтобы определить границу ошибки, используйте компонент ErrorBoundary для охвата существующего содержимого. Например, граница ошибки может быть добавлена вокруг содержимого основного макета приложения.

Приложение продолжит работать в обычном режиме, но граница ошибки будет обрабатывать необработанные исключения.

Рассмотрим следующий пример, в котором компонент Counter создает исключение, если число увеличивается до пяти.

Если необработанное исключение создается для currentCount более пяти:

  • Созданное исключение обрабатывается границей ошибки.
  • Отображается пользовательский интерфейс ошибки ( An error has occurred. ).

По умолчанию компонент ErrorBoundary отображает пустой элемент

Можно также изменить содержимое ошибки по умолчанию, задав свойство ErrorContent :

Поскольку в предыдущих примерах граница ошибки определена в макете, пользовательский интерфейс ошибки отображается независимо от того, на какую страницу переходит пользователь. В большинстве случаев рекомендуется сузить границы ошибок. Если вы используете широкие границы ошибки, вы можете сбросить их до состояния, где ошибка отсутствует, при последующих событиях навигации по странице, вызвав метод границы ошибки Recover:

Альтернативная глобальная обработка исключений

Альтернативой использованию границ ошибок (ErrorBoundary) является передача пользовательского компонента ошибки в качестве CascadingValue дочерним компонентам. Преимущество использования компонента по сравнению с использованием внедренной службы или реализации пользовательского средства ведения журнала заключается в том, что при возникновении ошибки каскадный компонент может отрисовывать содержимое и применять стили CSS.

В следующем примере компонента Error просто регистрируются ошибки, но методы компонента могут обрабатывать ошибки любым способом, требуемым для приложения, в том числе с использованием нескольких методов обработки ошибок.

В компоненте App создайте программу-оболочку для компонента Router с помощью компонента Error . Благодаря этому компонент Error сможет переходить к любому компоненту приложения, в котором компонент Error получен как CascadingParameter .

Чтобы обработать ошибки в компоненте, выполните приведенные ниже действия.

Назначьте компонент Error как CascadingParameter в блоке @code . В примере компонента Counter в приложении, основанном на шаблоне проекта Blazor, добавьте следующее свойство Error :

Вызовите метод обработки ошибок в любом блоке catch с соответствующим типом исключения. В примере компонента Error есть только один метод ProcessError . Однако компонент обработки ошибок может предоставить любое количество соответствующих методов, чтобы удовлетворить альтернативные требования к обработке ошибок во всем приложении. В следующем примере компонента Counter создается исключение, которое перехватывается, когда число больше пяти:

Используя предыдущий компонент Error с предыдущими изменениями, внесенными в компонент Counter , консоль инструментов разработчика обозревателя указывает на перехваченную, зарегистрированную ошибку:

Если метод ProcessError напрямую участвует в отрисовке, например показывает пользовательскую панель сообщений об ошибках или изменяет стили CSS отрисованных элементов, вызовите StateHasChanged в конце метода ProcessErrors для повторной отрисовки пользовательского интерфейса.

Так как подходы в этом разделе предусматривают обработку ошибок с помощью инструкции try-catch , соединение SignalR приложения Blazor Server между клиентом и сервером не прерывается при возникновении ошибки и канал остается активным. Другие необработанные исключения остаются неустранимыми для канала. Дополнительные сведения о том, как приложение Blazor Server реагирует на необработанные исключения,.

Регистрация ошибок с помощью постоянного поставщика

При возникновении необработанного исключения оно заносится в журнал экземпляров ILogger, настроенных в контейнере службы. По умолчанию приложения Blazor записываются в выходные данные консоли с помощью поставщика ведения журнала консоли. Рассмотрите возможность входа в расположение на сервере (или в серверный веб-API для приложений Blazor WebAssembly) с помощью поставщика, управляющего размером журнала и сменой журналов. Кроме того, приложение может использовать службу управления производительностью приложений (APM), например Azure Application Insights (Azure Monitor).

Встроенные возможности Application Insights для поддержки приложений Blazor WebAssembly и собственной платформы Blazor для Google Analytics могут стать доступными в будущих выпусках этих технологических решений. Дополнительные сведения см. в статьях Поддержка App Insights на стороне клиента Blazor WASM (microsoft/ApplicationInsights-dotnet #2143) и Веб-аналитика и диагностика (содержит ссылки на реализации сообщества) (dotnet/aspnetcore #5461). В то же время приложение Blazor WebAssembly на стороне клиента может использовать пакет SDK JavaScript Application Insights и взаимодействие JS для записи ошибок непосредственно в Application Insights из клиентского приложения.

Во время разработки в приложении Blazor Server приложение обычно отправляет полные сведения об исключениях в консоль браузера для поддержки отладки. В рабочей среде подробные сообщения об ошибках не отправляются клиентам, но все сведения об исключениях записываются на сервер.

Необходимо решить, какие инциденты следует заносить в журнал, и выбрать уровень серьезности регистрируемых инцидентов. Злоумышленники могут попытаться вызывать ошибки намеренно. Например, не заносите в журнал инцидент в результате ошибки, когда в URL-адресе компонента, отображающего сведения о продукте, указан неизвестный ProductId . Не все ошибки следует рассматривать как инциденты, подлежащие записи в журнал.

Дополнительные сведения см. в следующих статьях:

‡Применяется к приложениям Blazor Server и другим приложениям ASP.NET Core на стороне сервера, которые являются серверными приложениями веб-API для Blazor. Приложения Blazor WebAssembly могут перехватывать и отправлять сведения об ошибках на клиенте в веб-API, который регистрирует сведения об ошибке в постоянном поставщике ведения журнала.

Места, где могут возникнуть ошибки

Код платформы и приложения может активировать необработанные исключения в любом из следующих расположений, которые описаны в следующих разделах этой статьи.

Экземпляр компонента

Когда Blazor создает экземпляр компонента:

  • Вызывается конструктор компонента.
  • Вызываются конструкторы служб DI, которые передаются в конструктор компонента с помощью директивы @inject или атрибута [Inject] .

Ошибка в выполненном конструкторе или методе задания для любого свойства [Inject] приводит к возникновению необработанного исключения и предотвращает создание экземпляра компонента на платформе. Если приложение является приложением Blazor Server, происходит сбой канала. Если логика конструктора может вызывать исключения, приложение должно выполнить перехват исключений с помощью инструкции try-catch с обработкой ошибок и ведением журнала.

Методы жизненного цикла

В течение времени существования компонента Blazor вызывает методы жизненного цикла. Если какой-либо метод жизненного цикла вызывает исключение (синхронно или асинхронно), такое исключение является неустранимым для канала Blazor Server. Для компонентов, обрабатывающих ошибки в методах жизненного цикла, добавьте логику обработки ошибок.

В следующем примере OnParametersSetAsync вызывает метод для получения продукта:

  • Исключение, вызванное в методе ProductRepository.GetProductByIdAsync , обрабатывается оператором try-catch .
  • При выполнении блока catch :
    • loadFailed получает значение true , которое используется для вывода сообщения об ошибке пользователю.
    • Ошибка регистрируется в журнале.

Логика отрисовки

Декларативная разметка в файле компонента Razor ( .razor ) компилируется в метод C# с именем BuildRenderTree. Когда компонент отрисовывается, BuildRenderTree выполняет и создает структуру данных, описывающую элементы, текст и дочерние компоненты отрисованного компонента.

Логика отрисовки может вызывать исключение. Пример этого сценария происходит, когда @someObject.PropertyName вычисляется, но @someObject имеет значение null . Необработанное исключение, созданное логикой отрисовки, является неустранимым для канала приложения Blazor Server.

Чтобы предотвратить NullReferenceException в логике отрисовки, проверьте наличие объекта null перед обращением к его элементам. В следующем примере свойства person.Address недоступны, если person.Address имеет значение null :

В приведенном выше коде предполагается, что person не имеет значение null . Часто структура кода гарантирует, что объект существует на момент отрисовки компонента. В таких случаях нет необходимости проверять наличие null в логике отрисовки. В предыдущем примере person может гарантированно существовать, так как person создается при создании экземпляра компонента, как показано в следующем примере:

Обработчики событий

Код на стороне клиента активирует вызовы кода C# при создании обработчиков событий с помощью:

В этих сценариях код обработчика событий может вызывать необработанное исключение.

Если приложение вызывает код, который может завершиться ошибкой по внешним причинам, перехватите исключения с помощью инструкции try-catch с обработкой ошибок и ведением журнала.

Если обработчик событий вызывает необработанное исключение (например, запрос к базе данных завершается ошибкой), который не перехватывается и не обрабатывается кодом разработчика:

  • Платформа регистрирует исключение.
  • В приложении Blazor Server исключение является неустранимым для канала приложения.

Удаление компонентов

Компонент может быть удален из пользовательского интерфейса, например, потому, что пользователь перешел на другую страницу. Когда компонент, реализующий System.IDisposable, удаляется из пользовательского интерфейса, платформа вызывает метод Dispose компонента.

Если метод Dispose компонента создает необработанное исключение в приложении Blazor Server, это исключение является неустранимым для канала приложения.

Если логика удаления может вызывать исключения, приложение должно выполнить перехват исключений с помощью инструкции try-catch с обработкой ошибок и ведением журнала.

Дополнительные сведения об удалении компонентов см. в разделе Жизненный цикл компонента RazorASP.NET Core.

Взаимодействие с JavaScript

IJSRuntime регистрируется платформой Blazor. IJSRuntime.InvokeAsync позволяет коду .NET выполнять асинхронные вызовы к среде выполнения JavaScript (JS) в браузере пользователя.

К обработке ошибок с помощью InvokeAsync применяются следующие условия:

  • Если вызов к InvokeAsync выполняется синхронно, возникает исключение .NET. Вызов к InvokeAsync может завершиться ошибкой, например, поскольку передаваемые аргументы не могут быть сериализованы. Код разработчика должен перехватить исключение. Если код приложения в обработчике событий или в методе жизненного цикла компонента не обрабатывает исключение в приложении Blazor Server, то полученное исключение является неустранимым для канала приложения.
  • Если вызов InvokeAsync асинхронно завершается сбоем, .NET Task также завершается сбоем. Вызов к InvokeAsync может завершиться ошибкой, например, потому что код на стороне JS вызывает исключение или возвращает Promise , который был завершен как rejected . Код разработчика должен перехватить исключение. При использовании оператора await рекомендуется заключить вызов метода в инструкцию try-catch с обработкой ошибок и ведением журнала. В противном случае в приложении Blazor Server сбой кода приводит к возникновению необработанного исключения, которое является неустранимым для канала приложения.
  • По умолчанию вызовы к InvokeAsync должны завершаться в течение определенного периода или время ожидания вызова истекает. Период ожидания по умолчанию составляет одну минуту. Время ожидания защищает код от потери сетевого подключения или кода JS, который никогда не возвращает сообщение о завершении. Если время ожидания вызова истекает, полученный элемент System.Threading.Tasks завершается с исключением OperationCanceledException. Перехватите и обработайте исключение с ведением журнала.

Аналогичным образом код JS может инициировать вызовы методов .NET, указанных в атрибуте [JSInvokable] . Если эти методы .NET создают необработанное исключение:

  • В приложении Blazor Server исключение не считается неустранимым для канала приложения.
  • Promise на стороне JS отклоняется.

Вы можете использовать код обработки ошибок либо на стороне .NET, либо на стороне JS вызова метода.

Дополнительные сведения см. в следующих статьях:

Предварительная отрисовка

Компоненты Razor можно предварительно отрисовать с помощью вспомогательной функции тега компонента, чтобы их отрисованная разметка HTML возвращалась как часть исходного HTTP-запроса пользователя.

В Blazor Server предварительная отрисовка происходит следующим образом:

  • Создается новый канал для всех предварительно отрисованных компонентов, которые являются частью одной страницы.
  • Создается исходный HTML-код.
  • Канал рассматривается как disconnected , пока браузер пользователя не установит подключение SignalR к тому же серверу. Если соединение установлено, взаимодействие с каналом возобновляется, а HTML-разметка компонентов обновляется.

В предварительно отрисованных приложениях Blazor WebAssembly предварительная отрисовка происходит следующим образом:

  • Создается исходный HTML-код на сервере для всех предварительно отображенных компонентов, которые являются частью одной страницы.
  • Компонент делается интерактивным на клиенте после того, как браузер загрузил скомпилированный код приложения и среду выполнения .NET (если она еще не загружена) в фоновом режиме.

Если компонент создает необработанное исключение во время предварительной отрисовки, например во время метода жизненного цикла или в логике отрисовки:

  • В приложениях Blazor Sever исключение является неустранимым для канала. В предварительно отрисованных приложениях Blazor WebAssembly исключение препятствует визуализации компонента.
  • Исключение вызывается в стеке вызовов из ComponentTagHelper.

В обычных обстоятельствах при сбое предварительной отрисовки продолжение сборки и отрисовки компонента не имеет смысла, так как невозможно отрисовать рабочий компонент.

Чтобы допускать ошибки, которые могут возникнуть во время предварительной отрисовки, логика обработки ошибок должна размещаться внутри компонента, который может вызывать исключения. Используйте инструкции try-catch с обработкой ошибок и ведением журнала. Вместо того чтобы упаковывать ComponentTagHelper в инструкцию try-catch , поместите логику обработки ошибок в компонент, отрисовываемый ComponentTagHelper.

Сложные сценарии

Рекурсивная отрисовка

Компоненты можно вкладывать друг в друга рекурсивно. Это полезно для представления рекурсивных структур данных. Например, компонент TreeNode может отрисовывать другие компоненты TreeNode для каждого из дочерних элементов узла.

При рекурсивной отрисовке избегайте шаблонов кодирования, которые приводят к бесконечной рекурсии:

  • Не следует рекурсивно отрисовывать структуру данных, содержащую цикл. Например, не следует отрисовывать узел дерева, дочерние элементы которого содержат сами себя.
  • Не создавайте цепочку макетов, содержащих цикл. Например, не создавайте макет, макетом которого является он сам.
  • Не разрешайте пользователю нарушать инварианты рекурсии (правила) с помощью ввода вредоносных данных или вызовов взаимодействия JavaScript.

Бесконечные циклы во время отрисовки:

  • Приводят к тому, что процесс отрисовки будет выполняться бесконечно.
  • Эквивалентны созданию незавершенного цикла.

В этих сценариях происходит сбой потока Blazor WebAssembly или канала Blazor Server, и поток или канал обычно пытается выполнить следующие действия:

  • Использовать столько процессорных ресурсов, сколько разрешено операционной системой, в неограниченном объеме.
  • Использовать неограниченный объем памяти. Использование неограниченного объема памяти эквивалентно сценарию, в котором незавершенный цикл добавляет записи в коллекцию при каждой итерации.

Чтобы избежать бесконечного шаблона рекурсии, убедитесь, что рекурсивный код отрисовки содержит подходящие условия остановки.

Пользовательская логика дерева отрисовки

Большинство компонентов Razor реализуются как файлы компонента Razor ( .razor ) и компилируются платформой для создания логики, которая работает в RenderTreeBuilder для отрисовки выходных данных. Разработчик может вручную реализовать логику RenderTreeBuilder с помощью процедурного кода C#. Дополнительные сведения см. в разделе «Расширенные сценарии ASP.NET Core Blazor (построение дерева визуализации)».

Использование выполняемой вручную логики построителя дерева считается сложным и небезопасным сценарием, не рекомендуемым для обычной разработки компонентов.

При написании кода RenderTreeBuilder разработчик должен гарантировать правильность кода. Например, разработчик должен убедиться в том, что:

  • Вызовы к OpenElement и CloseElement правильно сбалансированы.
  • Атрибуты добавляются только в нужные места.

Неправильная логика конструктора выполняемой вручную логики построителя дерева отрисовки может вызвать произвольное неопределенное поведение, включая сбои, зависания приложения (Blazor WebAssembly) или сервера (Blazor Server) и уязвимости системы безопасности.

Считайте, что выполняемая вручную логика построителя дерева отрисовки имеет тот же уровень сложности и опасности, что и написание кода сборки или инструкций MSIL вручную.

Дополнительные ресурсы

†Применяется к серверным веб-API ASP.NET Core, которые клиентские приложения Blazor WebAssembly используют для ведения журнала.

Подробные сведения об ошибках во время разработки

Если во время разработки приложение Blazor работает неправильно, подробные сведения об ошибках в приложении могут помочь в устранении неполадок. При возникновении ошибки в приложении Blazor в нижней части экрана отображается светло-желтая полоса:

  • Во время разработки из этой полосы можно перейти в консоль браузера, где можно просмотреть исключение.
  • В рабочей среде эта полоса уведомляет пользователя о том, что произошла ошибка, и рекомендует обновить содержимое окна браузера.

Пользовательский интерфейс для этого процесса обработки ошибок входит в состав шаблонов проектов Blazor.

В приложении Blazor Server настройте интерфейс в файле Pages/_Layout.cshtml :

В приложении Blazor WebAssembly настройте интерфейс в файле wwwroot/index.html :

Элемент blazor-error-ui обычно скрыт из-за наличия стиля display: none класса CSS blazor-error-ui в таблице стилей сайта ( wwwroot/css/site.css для Blazor Server или wwwroot/css/app.css для Blazor WebAssembly). При возникновении ошибки платформа применяет display: block к элементу.

Подробное описание ошибок каналов

Этот раздел относится к приложениям Blazor Server.

Ошибки на стороне клиента не включают сведения о стеке вызовов и не предоставляют сведения о причине ошибки, но журналы сервера содержат эти сведения. В целях разработки конфиденциальные сведения об ошибках каналов можно сделать доступными для клиента, включив подробное описание ошибок.

Задайте для параметра CircuitOptions.DetailedErrors значение true . Дополнительные сведения и пример см. в разделе Руководство поBlazorSignalR ASP.NET Core .

В качестве альтернативы заданию параметра CircuitOptions.DetailedErrors можно задать для ключа конфигурации DetailedErrors значение true в файле параметров окружения разработки приложения ( appsettings.Development.json ). Кроме того, задайте для параметра SignalRведения журнала на стороне сервера ( Microsoft.AspNetCore.SignalR ) значение Отладка или Трассировка, чтобы обеспечить подробное ведение журнала SignalR.

Можно также задать DetailedErrors значение true для ключа конфигурации, используя переменную окружения ASPNETCORE_DETAILEDERRORS со значением true на серверах окружения разработки и промежуточной среды или в локальной системе.

Никогда не предоставляйте сведения об ошибках клиентам в Интернете, так как это подвергает безопасность угрозе.

Управление необработанными исключениями в коде разработчика

Чтобы приложение продолжало работу после возникновения ошибки, в нем должна быть логика обработки ошибок. В последующих разделах этой статьи описываются потенциальные источники необработанных исключений.

В рабочей среде не следует отображать сообщения об исключениях платформы или трассировки стека в пользовательском интерфейсе. Отображение сообщений об исключениях или трассировок стека может:

  • Раскрыть конфиденциальные сведения конечным пользователям.
  • Помочь злоумышленнику обнаружить слабые места в приложении, что может нарушить безопасность приложения, сервера или сети.

Blazor Server необработанные исключения

Этот раздел относится к приложениям Blazor Server.

Blazor Server — это платформа с отслеживанием состояния. Когда пользователи взаимодействуют с приложением, они поддерживают подключение к серверу, которое называется каналом. Канал содержит экземпляры активных компонентов, а также многие другие аспекты состояния, например:

  • Последние отображаемые выходные данные компонентов.
  • Текущий набор делегатов обработки событий, которые могут вызываться событиями на стороне клиента.

Если пользователь открывает приложение на нескольких вкладках браузера, он создает несколько независимых каналов.

Blazor обрабатывает большинство необработанных исключений как неустранимые для канала, где они происходят. Если канал завершается из-за необработанного исключения, пользователь может продолжить взаимодействие с приложением только путем перезагрузки страницы для создания нового канала. Это не влияет на остальные каналы для других пользователей или других вкладок браузера. Этот сценарий аналогичен сценарию с настольным приложением, которое аварийно завершает работу. Такое приложение необходимо перезапустить, но остальные приложения это не затрагивает.

Платформа завершает канал при возникновении необработанного исключения по следующим причинам:

  • Необработанное исключение часто оставляет канал в неопределенном состоянии.
  • После необработанного исключения нормальную работу приложения невозможно гарантировать.
  • Дальнейшая работа канала в неопределенном состоянии может стать причиной уязвимостей системы безопасности.

Границы ошибок

Blazor — это клиентская платформа одностраничного приложения (SPA). Браузер служит узлом приложения и, таким образом, действует как конвейер обработки для отдельных компонентов Razor на основе запросов URI для навигации и статических ресурсов. В отличие от приложений ASP.NET Core, которые работают на сервере с конвейером обработки ПО промежуточного слоя, конвейера ПО промежуточного слоя, обрабатывающего запросы компонентов Razor, которые можно использовать для глобальной обработки ошибок, не существует. Однако в качестве каскадного значения для централизованной обработки ошибок приложение может использовать компонент обработки ошибок.

Границы ошибок предоставляют удобный подход к обработке исключений. Компонент ErrorBoundary:

  • Отображает свое дочернее содержимое при возникновении ошибки.
  • Отображает пользовательский интерфейс ошибки при возникновении необработанного исключения.

Чтобы определить границу ошибки, используйте компонент ErrorBoundary для охвата существующего содержимого. Например, граница ошибки может быть добавлена вокруг содержимого основного макета приложения.

Приложение продолжит работать в обычном режиме, но граница ошибки будет обрабатывать необработанные исключения.

Рассмотрим следующий пример, в котором компонент Counter создает исключение, если число увеличивается до пяти.

Если необработанное исключение создается для currentCount более пяти:

  • Созданное исключение обрабатывается границей ошибки.
  • Отображается пользовательский интерфейс ошибки ( An error has occurred. ).

По умолчанию компонент ErrorBoundary отображает пустой элемент

Можно также изменить содержимое ошибки по умолчанию, задав свойство ErrorContent :

Поскольку в предыдущих примерах граница ошибки определена в макете, пользовательский интерфейс ошибки отображается независимо от того, на какую страницу переходит пользователь. В большинстве случаев рекомендуется сузить границы ошибок. Если вы используете широкие границы ошибки, вы можете сбросить их до состояния, где ошибка отсутствует, при последующих событиях навигации по странице, вызвав метод границы ошибки Recover:

Альтернативная глобальная обработка исключений

Альтернативой использованию границ ошибок (ErrorBoundary) является передача пользовательского компонента ошибки в качестве CascadingValue дочерним компонентам. Преимущество использования компонента по сравнению с использованием внедренной службы или реализации пользовательского средства ведения журнала заключается в том, что при возникновении ошибки каскадный компонент может отрисовывать содержимое и применять стили CSS.

В следующем примере компонента Error просто регистрируются ошибки, но методы компонента могут обрабатывать ошибки любым способом, требуемым для приложения, в том числе с использованием нескольких методов обработки ошибок.

В компоненте App создайте программу-оболочку для компонента Router с помощью компонента Error . Благодаря этому компонент Error сможет переходить к любому компоненту приложения, в котором компонент Error получен как CascadingParameter .

Чтобы обработать ошибки в компоненте, выполните приведенные ниже действия.

Назначьте компонент Error как CascadingParameter в блоке @code . В примере компонента Counter в приложении, основанном на шаблоне проекта Blazor, добавьте следующее свойство Error :

Вызовите метод обработки ошибок в любом блоке catch с соответствующим типом исключения. В примере компонента Error есть только один метод ProcessError . Однако компонент обработки ошибок может предоставить любое количество соответствующих методов, чтобы удовлетворить альтернативные требования к обработке ошибок во всем приложении. В следующем примере компонента Counter создается исключение, которое перехватывается, когда число больше пяти:

Используя предыдущий компонент Error с предыдущими изменениями, внесенными в компонент Counter , консоль инструментов разработчика обозревателя указывает на перехваченную, зарегистрированную ошибку:

Если метод ProcessError напрямую участвует в отрисовке, например показывает пользовательскую панель сообщений об ошибках или изменяет стили CSS отрисованных элементов, вызовите StateHasChanged в конце метода ProcessErrors для повторной отрисовки пользовательского интерфейса.

Так как подходы в этом разделе предусматривают обработку ошибок с помощью инструкции try-catch , соединение SignalR приложения Blazor Server между клиентом и сервером не прерывается при возникновении ошибки и канал остается активным. Другие необработанные исключения остаются неустранимыми для канала. Дополнительные сведения о том, как приложение Blazor Server реагирует на необработанные исключения,.

Регистрация ошибок с помощью постоянного поставщика

При возникновении необработанного исключения оно заносится в журнал экземпляров ILogger, настроенных в контейнере службы. По умолчанию приложения Blazor записываются в выходные данные консоли с помощью поставщика ведения журнала консоли. Рассмотрите возможность входа в расположение на сервере (или в серверный веб-API для приложений Blazor WebAssembly) с помощью поставщика, управляющего размером журнала и сменой журналов. Кроме того, приложение может использовать службу управления производительностью приложений (APM), например Azure Application Insights (Azure Monitor).

Встроенные возможности Application Insights для поддержки приложений Blazor WebAssembly и собственной платформы Blazor для Google Analytics могут стать доступными в будущих выпусках этих технологических решений. Дополнительные сведения см. в статьях Поддержка App Insights на стороне клиента Blazor WASM (microsoft/ApplicationInsights-dotnet #2143) и Веб-аналитика и диагностика (содержит ссылки на реализации сообщества) (dotnet/aspnetcore #5461). В то же время приложение Blazor WebAssembly на стороне клиента может использовать пакет SDK JavaScript Application Insights и взаимодействие JS для записи ошибок непосредственно в Application Insights из клиентского приложения.

Во время разработки в приложении Blazor Server приложение обычно отправляет полные сведения об исключениях в консоль браузера для поддержки отладки. В рабочей среде подробные сообщения об ошибках не отправляются клиентам, но все сведения об исключениях записываются на сервер.

Необходимо решить, какие инциденты следует заносить в журнал, и выбрать уровень серьезности регистрируемых инцидентов. Злоумышленники могут попытаться вызывать ошибки намеренно. Например, не заносите в журнал инцидент в результате ошибки, когда в URL-адресе компонента, отображающего сведения о продукте, указан неизвестный ProductId . Не все ошибки следует рассматривать как инциденты, подлежащие записи в журнал.

Дополнительные сведения см. в следующих статьях:

‡Применяется к приложениям Blazor Server и другим приложениям ASP.NET Core на стороне сервера, которые являются серверными приложениями веб-API для Blazor. Приложения Blazor WebAssembly могут перехватывать и отправлять сведения об ошибках на клиенте в веб-API, который регистрирует сведения об ошибке в постоянном поставщике ведения журнала.

Места, где могут возникнуть ошибки

Код платформы и приложения может активировать необработанные исключения в любом из следующих расположений, которые описаны в следующих разделах этой статьи.

Экземпляр компонента

Когда Blazor создает экземпляр компонента:

  • Вызывается конструктор компонента.
  • Вызываются конструкторы служб DI, которые передаются в конструктор компонента с помощью директивы @inject или атрибута [Inject] .

Ошибка в выполненном конструкторе или методе задания для любого свойства [Inject] приводит к возникновению необработанного исключения и предотвращает создание экземпляра компонента на платформе. Если приложение является приложением Blazor Server, происходит сбой канала. Если логика конструктора может вызывать исключения, приложение должно выполнить перехват исключений с помощью инструкции try-catch с обработкой ошибок и ведением журнала.

Методы жизненного цикла

В течение времени существования компонента Blazor вызывает методы жизненного цикла. Если какой-либо метод жизненного цикла вызывает исключение (синхронно или асинхронно), такое исключение является неустранимым для канала Blazor Server. Для компонентов, обрабатывающих ошибки в методах жизненного цикла, добавьте логику обработки ошибок.

В следующем примере OnParametersSetAsync вызывает метод для получения продукта:

  • Исключение, вызванное в методе ProductRepository.GetProductByIdAsync , обрабатывается оператором try-catch .
  • При выполнении блока catch :
    • loadFailed получает значение true , которое используется для вывода сообщения об ошибке пользователю.
    • Ошибка регистрируется в журнале.

Логика отрисовки

Декларативная разметка в файле компонента Razor ( .razor ) компилируется в метод C# с именем BuildRenderTree. Когда компонент отрисовывается, BuildRenderTree выполняет и создает структуру данных, описывающую элементы, текст и дочерние компоненты отрисованного компонента.

Логика отрисовки может вызывать исключение. Пример этого сценария происходит, когда @someObject.PropertyName вычисляется, но @someObject имеет значение null . Необработанное исключение, созданное логикой отрисовки, является неустранимым для канала приложения Blazor Server.

Чтобы предотвратить NullReferenceException в логике отрисовки, проверьте наличие объекта null перед обращением к его элементам. В следующем примере свойства person.Address недоступны, если person.Address имеет значение null :

В приведенном выше коде предполагается, что person не имеет значение null . Часто структура кода гарантирует, что объект существует на момент отрисовки компонента. В таких случаях нет необходимости проверять наличие null в логике отрисовки. В предыдущем примере person может гарантированно существовать, так как person создается при создании экземпляра компонента, как показано в следующем примере:

Обработчики событий

Код на стороне клиента активирует вызовы кода C# при создании обработчиков событий с помощью:

В этих сценариях код обработчика событий может вызывать необработанное исключение.

Если приложение вызывает код, который может завершиться ошибкой по внешним причинам, перехватите исключения с помощью инструкции try-catch с обработкой ошибок и ведением журнала.

Если обработчик событий вызывает необработанное исключение (например, запрос к базе данных завершается ошибкой), который не перехватывается и не обрабатывается кодом разработчика:

  • Платформа регистрирует исключение.
  • В приложении Blazor Server исключение является неустранимым для канала приложения.

Удаление компонентов

Компонент может быть удален из пользовательского интерфейса, например, потому, что пользователь перешел на другую страницу. Когда компонент, реализующий System.IDisposable, удаляется из пользовательского интерфейса, платформа вызывает метод Dispose компонента.

Если метод Dispose компонента создает необработанное исключение в приложении Blazor Server, это исключение является неустранимым для канала приложения.

Если логика удаления может вызывать исключения, приложение должно выполнить перехват исключений с помощью инструкции try-catch с обработкой ошибок и ведением журнала.

Дополнительные сведения об удалении компонентов см. в разделе Жизненный цикл компонента RazorASP.NET Core.

Взаимодействие с JavaScript

IJSRuntime регистрируется платформой Blazor. IJSRuntime.InvokeAsync позволяет коду .NET выполнять асинхронные вызовы к среде выполнения JavaScript (JS) в браузере пользователя.

К обработке ошибок с помощью InvokeAsync применяются следующие условия:

  • Если вызов к InvokeAsync выполняется синхронно, возникает исключение .NET. Вызов к InvokeAsync может завершиться ошибкой, например, поскольку передаваемые аргументы не могут быть сериализованы. Код разработчика должен перехватить исключение. Если код приложения в обработчике событий или в методе жизненного цикла компонента не обрабатывает исключение в приложении Blazor Server, то полученное исключение является неустранимым для канала приложения.
  • Если вызов InvokeAsync асинхронно завершается сбоем, .NET Task также завершается сбоем. Вызов к InvokeAsync может завершиться ошибкой, например, потому что код на стороне JS вызывает исключение или возвращает Promise , который был завершен как rejected . Код разработчика должен перехватить исключение. При использовании оператора await рекомендуется заключить вызов метода в инструкцию try-catch с обработкой ошибок и ведением журнала. В противном случае в приложении Blazor Server сбой кода приводит к возникновению необработанного исключения, которое является неустранимым для канала приложения.
  • По умолчанию вызовы к InvokeAsync должны завершаться в течение определенного периода или время ожидания вызова истекает. Период ожидания по умолчанию составляет одну минуту. Время ожидания защищает код от потери сетевого подключения или кода JS, который никогда не возвращает сообщение о завершении. Если время ожидания вызова истекает, полученный элемент System.Threading.Tasks завершается с исключением OperationCanceledException. Перехватите и обработайте исключение с ведением журнала.

Аналогичным образом код JS может инициировать вызовы методов .NET, указанных в атрибуте [JSInvokable] . Если эти методы .NET создают необработанное исключение:

  • В приложении Blazor Server исключение не считается неустранимым для канала приложения.
  • Promise на стороне JS отклоняется.

Вы можете использовать код обработки ошибок либо на стороне .NET, либо на стороне JS вызова метода.

Дополнительные сведения см. в следующих статьях:

Предварительная отрисовка

Компоненты Razor можно предварительно отрисовать с помощью вспомогательной функции тега компонента, чтобы их отрисованная разметка HTML возвращалась как часть исходного HTTP-запроса пользователя.

В Blazor Server предварительная отрисовка происходит следующим образом:

  • Создается новый канал для всех предварительно отрисованных компонентов, которые являются частью одной страницы.
  • Создается исходный HTML-код.
  • Канал рассматривается как disconnected , пока браузер пользователя не установит подключение SignalR к тому же серверу. Если соединение установлено, взаимодействие с каналом возобновляется, а HTML-разметка компонентов обновляется.

В предварительно отрисованных приложениях Blazor WebAssembly предварительная отрисовка происходит следующим образом:

  • Создается исходный HTML-код на сервере для всех предварительно отображенных компонентов, которые являются частью одной страницы.
  • Компонент делается интерактивным на клиенте после того, как браузер загрузил скомпилированный код приложения и среду выполнения .NET (если она еще не загружена) в фоновом режиме.

Если компонент создает необработанное исключение во время предварительной отрисовки, например во время метода жизненного цикла или в логике отрисовки:

  • В приложениях Blazor Sever исключение является неустранимым для канала. В предварительно отрисованных приложениях Blazor WebAssembly исключение препятствует визуализации компонента.
  • Исключение вызывается в стеке вызовов из ComponentTagHelper.

В обычных обстоятельствах при сбое предварительной отрисовки продолжение сборки и отрисовки компонента не имеет смысла, так как невозможно отрисовать рабочий компонент.

Чтобы допускать ошибки, которые могут возникнуть во время предварительной отрисовки, логика обработки ошибок должна размещаться внутри компонента, который может вызывать исключения. Используйте инструкции try-catch с обработкой ошибок и ведением журнала. Вместо того чтобы упаковывать ComponentTagHelper в инструкцию try-catch , поместите логику обработки ошибок в компонент, отрисовываемый ComponentTagHelper.

Сложные сценарии

Рекурсивная отрисовка

Компоненты можно вкладывать друг в друга рекурсивно. Это полезно для представления рекурсивных структур данных. Например, компонент TreeNode может отрисовывать другие компоненты TreeNode для каждого из дочерних элементов узла.

При рекурсивной отрисовке избегайте шаблонов кодирования, которые приводят к бесконечной рекурсии:

  • Не следует рекурсивно отрисовывать структуру данных, содержащую цикл. Например, не следует отрисовывать узел дерева, дочерние элементы которого содержат сами себя.
  • Не создавайте цепочку макетов, содержащих цикл. Например, не создавайте макет, макетом которого является он сам.
  • Не разрешайте пользователю нарушать инварианты рекурсии (правила) с помощью ввода вредоносных данных или вызовов взаимодействия JavaScript.

Бесконечные циклы во время отрисовки:

  • Приводят к тому, что процесс отрисовки будет выполняться бесконечно.
  • Эквивалентны созданию незавершенного цикла.

В этих сценариях происходит сбой потока Blazor WebAssembly или канала Blazor Server, и поток или канал обычно пытается выполнить следующие действия:

  • Использовать столько процессорных ресурсов, сколько разрешено операционной системой, в неограниченном объеме.
  • Использовать неограниченный объем памяти. Использование неограниченного объема памяти эквивалентно сценарию, в котором незавершенный цикл добавляет записи в коллекцию при каждой итерации.

Чтобы избежать бесконечного шаблона рекурсии, убедитесь, что рекурсивный код отрисовки содержит подходящие условия остановки.

Пользовательская логика дерева отрисовки

Большинство компонентов Razor реализуются как файлы компонента Razor ( .razor ) и компилируются платформой для создания логики, которая работает в RenderTreeBuilder для отрисовки выходных данных. Разработчик может вручную реализовать логику RenderTreeBuilder с помощью процедурного кода C#. Дополнительные сведения см. в разделе «Расширенные сценарии ASP.NET Core Blazor (построение дерева визуализации)».

Использование выполняемой вручную логики построителя дерева считается сложным и небезопасным сценарием, не рекомендуемым для обычной разработки компонентов.

При написании кода RenderTreeBuilder разработчик должен гарантировать правильность кода. Например, разработчик должен убедиться в том, что:

  • Вызовы к OpenElement и CloseElement правильно сбалансированы.
  • Атрибуты добавляются только в нужные места.

Неправильная логика конструктора выполняемой вручную логики построителя дерева отрисовки может вызвать произвольное неопределенное поведение, включая сбои, зависания приложения (Blazor WebAssembly) или сервера (Blazor Server) и уязвимости системы безопасности.

Считайте, что выполняемая вручную логика построителя дерева отрисовки имеет тот же уровень сложности и опасности, что и написание кода сборки или инструкций MSIL вручную.

Дополнительные ресурсы

†Применяется к серверным веб-API ASP.NET Core, которые клиентские приложения Blazor WebAssembly используют для ведения журнала.

Подробные сведения об ошибках во время разработки приложений Blazor WebAssembly

Если во время разработки приложение Blazor работает неправильно, подробные сведения об ошибках в приложении могут помочь в устранении неполадок. При возникновении ошибки в приложении Blazor в нижней части экрана отображается светло-желтая полоса:

  • Во время разработки из этой полосы можно перейти в консоль браузера, где можно просмотреть исключение.
  • В рабочей среде эта полоса уведомляет пользователя о том, что произошла ошибка, и рекомендует обновить содержимое окна браузера.

Пользовательский интерфейс для этого процесса обработки ошибок входит в состав шаблонов проектов Blazor.

В приложении Blazor WebAssembly настройте интерфейс в файле wwwroot/index.html :

Элемент blazor-error-ui обычно скрыт из-за наличия стиля display: none класса CSS blazor-error-ui в таблице стилей приложения ( wwwroot/css/app.css ). При возникновении ошибки платформа применяет display: block к элементу.

Управление необработанными исключениями в коде разработчика

Чтобы приложение продолжало работу после возникновения ошибки, в нем должна быть логика обработки ошибок. В последующих разделах этой статьи описываются потенциальные источники необработанных исключений.

В рабочей среде не следует отображать сообщения об исключениях платформы или трассировки стека в пользовательском интерфейсе. Отображение сообщений об исключениях или трассировок стека может:

  • Раскрыть конфиденциальные сведения конечным пользователям.
  • Помочь злоумышленнику обнаружить слабые места в приложении, что может нарушить безопасность приложения, сервера или сети.

Глобальная обработка исключений

Blazor — это клиентская платформа одностраничного приложения (SPA). Браузер служит узлом приложения и, таким образом, действует как конвейер обработки для отдельных компонентов Razor на основе запросов URI для навигации и статических ресурсов. В отличие от приложений ASP.NET Core, которые работают на сервере с конвейером обработки ПО промежуточного слоя, конвейера ПО промежуточного слоя, обрабатывающего запросы компонентов Razor, которые можно использовать для глобальной обработки ошибок, не существует. Однако в качестве каскадного значения для централизованной обработки ошибок приложение может использовать компонент обработки ошибок.

Следующий компонент Error передает себя дочерним компонентам в качестве CascadingValue . В следующем примере просто регистрируется ошибка, но методы компонента могут обрабатывать ошибки любым способом, требуемым для приложения, в том числе с использованием нескольких методов обработки ошибок. Преимущество использования компонента по сравнению с использованием внедренной службы или реализации пользовательского средства ведения журнала заключается в том, что при возникновении ошибки каскадный компонент может отрисовывать содержимое и применять стили CSS.

В компоненте App создайте программу-оболочку для компонента Router с помощью компонента Error . Благодаря этому компонент Error сможет переходить к любому компоненту приложения, в котором компонент Error получен как CascadingParameter .

Чтобы обработать ошибки в компоненте, выполните приведенные ниже действия.

Назначьте компонент Error как CascadingParameter в блоке @code :

Вызовите метод обработки ошибок в любом блоке catch с соответствующим типом исключения. В примере компонента Error есть только один метод ProcessError . Однако компонент обработки ошибок может предоставить любое количество соответствующих методов, чтобы удовлетворить альтернативные требования к обработке ошибок во всем приложении.

Используя компонент Error и метод ProcessError из предыдущего примера, консоль инструментов разработчика обозревателя указывает на перехваченную, зарегистрированную ошибку:

Сбой: BlazorSample.Shared.Error[0] Error:ProcessError — Тип: System.NullReferenceException Сообщение: Ссылка на объект не указывает на экземпляр объекта.

Если метод ProcessError напрямую участвует в отрисовке, например показывает пользовательскую панель сообщений об ошибках или изменяет стили CSS отрисованных элементов, вызовите StateHasChanged в конце метода ProcessErrors для повторной отрисовки пользовательского интерфейса.

Так как подходы в этом разделе предусматривают обработку ошибок с помощью инструкции try-catch , соединение SignalR приложения Blazor Server между клиентом и сервером не прерывается при возникновении ошибки и канал остается активным. Необработанное исключение является неустранимым для канала. Дополнительные сведения о том, как приложение Blazor Server реагирует на необработанные исключения,.

Регистрация ошибок с помощью постоянного поставщика (Blazor WebAssembly)

При возникновении необработанного исключения оно заносится в журнал экземпляров ILogger, настроенных в контейнере службы. По умолчанию приложения Blazor записываются в выходные данные консоли с помощью поставщика ведения журнала консоли. Возможно, следует сохранять записи журнала в более постоянное расположение на сервере, отправляя сведения об ошибке в серверный веб-API, который использует поставщик ведения журнала с возможностью управления размером журнала и ротации журналов. Кроме того, серверное приложение веб-API может использовать службу управления производительностью приложений (APM), например Azure Application Insights (Azure Monitor)†, для записи сведений об ошибках, получаемых от клиентов.

Необходимо решить, какие инциденты следует заносить в журнал, и выбрать уровень серьезности регистрируемых инцидентов. Злоумышленники могут попытаться вызывать ошибки намеренно. Например, не заносите в журнал инцидент в результате ошибки, когда в URL-адресе компонента, отображающего сведения о продукте, указан неизвестный ProductId . Не все ошибки следует рассматривать как инциденты, подлежащие записи в журнал.

Дополнительные сведения см. в следующих статьях:

†Встроенные возможности Application Insights для поддержки приложений Blazor WebAssembly и поддержки собственной платформы Blazor для Google Analytics могут стать доступными в будущих выпусках этих технологических решений. Дополнительные сведения см. в статьях Поддержка App Insights на стороне клиента Blazor WASM (microsoft/ApplicationInsights-dotnet #2143) и Веб-аналитика и диагностика (содержит ссылки на реализации сообщества) (dotnet/aspnetcore #5461). В то же время приложение Blazor WebAssembly на стороне клиента может использовать пакет SDK JavaScript Application Insights и взаимодействие JS для записи ошибок непосредственно в Application Insights из клиентского приложения.

‡Применяется к приложениям ASP.NET Core на стороне сервера, которые являются серверными приложениями веб-API для приложений Blazor. Приложения на стороне клиента регистрируют и отправляют сведения об ошибках в веб-API, который регистрирует сведения об ошибке в постоянном поставщике ведения журнала.

Места в приложениях Blazor WebAssembly, где могут появляться ошибки

Код платформы и приложения может активировать необработанные исключения в любом из следующих расположений, которые описаны в следующих разделах этой статьи.

Экземпляр компонента (Blazor WebAssembly)

Когда Blazor создает экземпляр компонента:

  • Вызывается конструктор компонента.
  • Вызываются конструкторы служб DI, которые передаются в конструктор компонента с помощью директивы @inject или атрибута [Inject] .

Ошибка в выполненном конструкторе или методе задания для любого свойства [Inject] приводит к возникновению необработанного исключения и предотвращает создание экземпляра компонента на платформе. Если логика конструктора может вызывать исключения, приложение должно выполнить перехват исключений с помощью инструкции try-catch с обработкой ошибок и ведением журнала.

Методы жизненного цикла (Blazor WebAssembly)

В течение времени существования компонента Blazor вызывает методы жизненного цикла. Для компонентов, обрабатывающих ошибки в методах жизненного цикла, добавьте логику обработки ошибок.

В следующем примере OnParametersSetAsync вызывает метод для получения продукта:

  • Исключение, вызванное в методе ProductRepository.GetProductByIdAsync , обрабатывается оператором try-catch .
  • При выполнении блока catch :
    • loadFailed получает значение true , которое используется для вывода сообщения об ошибке пользователю.
    • Ошибка регистрируется в журнале.

Логика отрисовки (Blazor WebAssembly)

Декларативная разметка в файле компонента Razor ( .razor ) компилируется в метод C# с именем BuildRenderTree. Когда компонент отрисовывается, BuildRenderTree выполняет и создает структуру данных, описывающую элементы, текст и дочерние компоненты отрисованного компонента.

Логика отрисовки может вызывать исключение. Пример этого сценария происходит, когда @someObject.PropertyName вычисляется, но @someObject имеет значение null .

Чтобы предотвратить NullReferenceException в логике отрисовки, проверьте наличие объекта null перед обращением к его элементам. В следующем примере свойства person.Address недоступны, если person.Address имеет значение null :

В приведенном выше коде предполагается, что person не имеет значение null . Часто структура кода гарантирует, что объект существует на момент отрисовки компонента. В таких случаях нет необходимости проверять наличие null в логике отрисовки. В предыдущем примере person может гарантированно существовать, так как person создается при создании экземпляра компонента, как показано в следующем примере:

Обработчики событий (Blazor WebAssembly)

Код на стороне клиента активирует вызовы кода C# при создании обработчиков событий с помощью:

В этих сценариях код обработчика событий может вызывать необработанное исключение.

Если приложение вызывает код, который может завершиться ошибкой по внешним причинам, перехватите исключения с помощью инструкции try-catch с обработкой ошибок и ведением журнала.

Если пользовательский код не выполняет перехват и обработку исключения, платформа регистрирует исключение.

Удаление компонентов (Blazor WebAssembly)

Компонент может быть удален из пользовательского интерфейса, например, потому, что пользователь перешел на другую страницу. Когда компонент, реализующий System.IDisposable, удаляется из пользовательского интерфейса, платформа вызывает метод Dispose компонента.

Если логика удаления может вызывать исключения, приложение должно выполнить перехват исключений с помощью инструкции try-catch с обработкой ошибок и ведением журнала.

Дополнительные сведения об удалении компонентов см. в разделе Жизненный цикл компонента RazorASP.NET Core.

Взаимодействие с JavaScript (Blazor WebAssembly)

IJSRuntime регистрируется платформой Blazor. IJSRuntime.InvokeAsync позволяет коду .NET выполнять асинхронные вызовы в среде выполнения JavaScript в браузере пользователя.

К обработке ошибок с помощью InvokeAsync применяются следующие условия:

  • Если вызов к InvokeAsync выполняется синхронно, возникает исключение .NET. Вызов к InvokeAsync может завершиться ошибкой, например, поскольку передаваемые аргументы не могут быть сериализованы. Код разработчика должен перехватить исключение.
  • Если вызов InvokeAsync асинхронно завершается сбоем, .NET Task также завершается сбоем. Вызов к InvokeAsync может завершиться ошибкой, например, потому, что код на стороне JavaScript вызывает исключение или возвращает Promise , который был завершен как rejected . Код разработчика должен перехватить исключение. При использовании оператора await рекомендуется заключить вызов метода в инструкцию try-catch с обработкой ошибок и ведением журнала.
  • По умолчанию вызовы к InvokeAsync должны завершаться в течение определенного периода или время ожидания вызова истекает. Период ожидания по умолчанию составляет одну минуту. Время ожидания защищает код от потери сетевого подключения или кода JavaScript, который никогда не отправляет обратно сообщение о завершении. Если время ожидания вызова истекает, полученный элемент System.Threading.Tasks завершается с исключением OperationCanceledException. Перехватите и обработайте исключение с ведением журнала.

Аналогичным образом код JavaScript может инициировать вызовы методов .NET, указанных в атрибуте [JSInvokable] . Если эти методы .NET создают необработанное исключение, то Promise на стороне JavaScript отклоняется.

Вы можете использовать код обработки ошибок либо на стороне .NET, либо на стороне JavaScript вызова метода.

Дополнительные сведения см. в следующих статьях:

Подробные сведения об ошибках во время разработки приложений Blazor Server

Если во время разработки приложение Blazor работает неправильно, подробные сведения об ошибках в приложении могут помочь в устранении неполадок. При возникновении ошибки в приложении Blazor в нижней части экрана отображается светло-желтая полоса:

  • Во время разработки из этой полосы можно перейти в консоль браузера, где можно просмотреть исключение.
  • В рабочей среде эта полоса уведомляет пользователя о том, что произошла ошибка, и рекомендует обновить содержимое окна браузера.

Пользовательский интерфейс для этого процесса обработки ошибок входит в состав шаблонов проектов Blazor.

В приложении Blazor Server настройте интерфейс в файле Pages/_Host.cshtml :

Элемент blazor-error-ui обычно скрыт из-за наличия стиля display: none класса CSS blazor-error-ui в таблице стилей сайта ( wwwroot/css/site.css ). При возникновении ошибки платформа применяет display: block к элементу.

Подробное описание ошибок каналов в Blazor Server

Ошибки на стороне клиента не включают сведения о стеке вызовов и не предоставляют сведения о причине ошибки, но журналы сервера содержат эти сведения. В целях разработки конфиденциальные сведения об ошибках каналов можно сделать доступными для клиента, включив подробное описание ошибок.

Задайте для параметра CircuitOptions.DetailedErrors значение true . Дополнительные сведения и пример см. в разделе Руководство поBlazorSignalR ASP.NET Core .

В качестве альтернативы заданию параметра CircuitOptions.DetailedErrors можно задать для ключа конфигурации DetailedErrors значение true в файле параметров окружения разработки приложения ( appsettings.Development.json ). Кроме того, задайте для параметра SignalRведения журнала на стороне сервера ( Microsoft.AspNetCore.SignalR ) значение Отладка или Трассировка, чтобы обеспечить подробное ведение журнала SignalR.

Можно также задать DetailedErrors значение true для ключа конфигурации, используя переменную окружения ASPNETCORE_DETAILEDERRORS со значением true на серверах окружения разработки и промежуточной среды или в локальной системе.

Никогда не предоставляйте сведения об ошибках клиентам в Интернете, так как это подвергает безопасность угрозе.

Как приложение Blazor Server реагирует на необработанные исключения

Blazor Server — это платформа с отслеживанием состояния. Когда пользователи взаимодействуют с приложением, они поддерживают подключение к серверу, которое называется каналом. Канал содержит экземпляры активных компонентов, а также многие другие аспекты состояния, например:

  • Последние отображаемые выходные данные компонентов.
  • Текущий набор делегатов обработки событий, которые могут вызываться событиями на стороне клиента.

Если пользователь открывает приложение на нескольких вкладках браузера, он создает несколько независимых каналов.

Blazor обрабатывает большинство необработанных исключений как неустранимые для канала, где они происходят. Если канал завершается из-за необработанного исключения, пользователь может продолжить взаимодействие с приложением только путем перезагрузки страницы для создания нового канала. Это не влияет на остальные каналы для других пользователей или других вкладок браузера. Этот сценарий аналогичен сценарию с настольным приложением, которое аварийно завершает работу. Такое приложение необходимо перезапустить, но остальные приложения это не затрагивает.

Платформа завершает канал при возникновении необработанного исключения по следующим причинам:

  • Необработанное исключение часто оставляет канал в неопределенном состоянии.
  • После необработанного исключения нормальную работу приложения невозможно гарантировать.
  • Дальнейшая работа канала в неопределенном состоянии может стать причиной уязвимостей системы безопасности.

Регистрация ошибок с помощью постоянного поставщика (Blazor Server)

При возникновении необработанного исключения оно заносится в журнал экземпляров ILogger, настроенных в контейнере службы. По умолчанию приложения Blazor записываются в выходные данные консоли с помощью поставщика ведения журнала консоли. Возможно, следует сохранять записи журнала в более постоянное расположение на сервере с помощью поставщика, который управляет размером журнала и их ротацией. Кроме того, приложение может использовать службу управления производительностью приложений (APM), например Azure Application Insights (Azure Monitor).

Во время разработки приложение Blazor Server обычно отправляет полные сведения об исключениях в консоль браузера для поддержки отладки. В рабочей среде подробные сообщения об ошибках не отправляются клиентам, но все сведения об исключениях записываются на сервер.

Необходимо решить, какие инциденты следует заносить в журнал, и выбрать уровень серьезности регистрируемых инцидентов. Злоумышленники могут попытаться вызывать ошибки намеренно. Например, не заносите в журнал инцидент в результате ошибки, когда в URL-адресе компонента, отображающего сведения о продукте, указан неизвестный ProductId . Не все ошибки следует рассматривать как инциденты, подлежащие записи в журнал.

Дополнительные сведения см. в следующих статьях:

†Применяется к приложениям ASP.NET Core на стороне сервера, которые являются серверными приложениями веб-API для приложений Blazor.

Места в приложениях Blazor Server, где могут появляться ошибки

Код платформы и приложения может активировать необработанные исключения в любом из следующих расположений, которые описаны в следующих разделах этой статьи.

Экземпляр компонента (Blazor Server)

Когда Blazor создает экземпляр компонента:

  • Вызывается конструктор компонента.
  • Вызываются конструкторы любых не отдельных служб DI, которые передаются в конструктор компонента с помощью директивы @inject или атрибута [Inject] .

Сбой канала Blazor Server происходит, когда любой выполненный конструктор или метод задания для любого свойства [Inject] выдает необработанное исключение. Исключение является неустранимым, так как платформе не удается создать экземпляр компонента. Если логика конструктора может вызывать исключения, приложение должно выполнить перехват исключений с помощью инструкции try-catch с обработкой ошибок и ведением журнала.

Методы жизненного цикла (Blazor Server)

В течение времени существования компонента Blazor вызывает методы жизненного цикла. Если какой-либо метод жизненного цикла вызывает исключение (синхронно или асинхронно), такое исключение является неустранимым для канала Blazor Server. Для компонентов, обрабатывающих ошибки в методах жизненного цикла, добавьте логику обработки ошибок.

В следующем примере OnParametersSetAsync вызывает метод для получения продукта:

  • Исключение, вызванное в методе ProductRepository.GetProductByIdAsync , обрабатывается оператором try-catch .
  • При выполнении блока catch :
    • loadFailed получает значение true , которое используется для вывода сообщения об ошибке пользователю.
    • Ошибка регистрируется в журнале.

Логика отрисовки (Blazor Server)

Декларативная разметка в файле компонента Razor ( .razor ) компилируется в метод C# с именем BuildRenderTree. Когда компонент отрисовывается, BuildRenderTree выполняет и создает структуру данных, описывающую элементы, текст и дочерние компоненты отрисованного компонента.

Логика отрисовки может вызывать исключение. Пример этого сценария происходит, когда @someObject.PropertyName вычисляется, но @someObject имеет значение null . Необработанное исключение, созданное логикой отрисовки, является неустранимым для канала Blazor Server.

Чтобы предотвратить NullReferenceException в логике отрисовки, проверьте наличие объекта null перед обращением к его элементам. В следующем примере свойства person.Address недоступны, если person.Address имеет значение null :

В приведенном выше коде предполагается, что person не имеет значение null . Часто структура кода гарантирует, что объект существует на момент отрисовки компонента. В таких случаях нет необходимости проверять наличие null в логике отрисовки. В предыдущем примере person может гарантированно существовать, так как person создается при создании экземпляра компонента, как показано в следующем примере:

Обработчики событий (Blazor Server)

Код на стороне клиента активирует вызовы кода C# при создании обработчиков событий с помощью:

В этих сценариях код обработчика событий может вызывать необработанное исключение.

Если обработчик событий создает необработанное исключение (например, запрос к базе данных завершается ошибкой), такое исключение является неустранимым для канала Blazor Server. Если приложение вызывает код, который может завершиться ошибкой по внешним причинам, перехватите исключения с помощью инструкции try-catch с обработкой ошибок и ведением журнала.

Если пользовательский код не выполняет перехват и обработку исключения, платформа регистрирует исключение и завершает канал.

Удаление компонентов (Blazor Server)

Компонент может быть удален из пользовательского интерфейса, например, потому, что пользователь перешел на другую страницу. Когда компонент, реализующий System.IDisposable, удаляется из пользовательского интерфейса, платформа вызывает метод Dispose компонента.

Если метод Dispose компонента создает необработанное исключение, такое исключение является неустранимым для канала Blazor Server. Если логика удаления может вызывать исключения, приложение должно выполнить перехват исключений с помощью инструкции try-catch с обработкой ошибок и ведением журнала.

Дополнительные сведения об удалении компонентов см. в разделе Жизненный цикл компонента RazorASP.NET Core.

Взаимодействие с JavaScript (Blazor Server)

IJSRuntime регистрируется платформой Blazor. IJSRuntime.InvokeAsync позволяет коду .NET выполнять асинхронные вызовы в среде выполнения JavaScript в браузере пользователя.

К обработке ошибок с помощью InvokeAsync применяются следующие условия:

  • Если вызов к InvokeAsync выполняется синхронно, возникает исключение .NET. Вызов к InvokeAsync может завершиться ошибкой, например, поскольку передаваемые аргументы не могут быть сериализованы. Код разработчика должен перехватить исключение. Если код приложения в обработчике событий или методе жизненного цикла компонента не обрабатывает исключение, полученное исключение является неустранимым для канала Blazor Server.
  • Если вызов InvokeAsync асинхронно завершается сбоем, .NET Task также завершается сбоем. Вызов к InvokeAsync может завершиться ошибкой, например, потому, что код на стороне JavaScript вызывает исключение или возвращает Promise , который был завершен как rejected . Код разработчика должен перехватить исключение. При использовании оператора await рекомендуется заключить вызов метода в инструкцию try-catch с обработкой ошибок и ведением журнала. В противном случае сбой кода приводит к возникновению необработанного исключения, которое является неустранимым для канала Blazor Server.
  • По умолчанию вызовы к InvokeAsync должны завершаться в течение определенного периода или время ожидания вызова истекает. Период ожидания по умолчанию составляет одну минуту. Время ожидания защищает код от потери сетевого подключения или кода JavaScript, который никогда не отправляет обратно сообщение о завершении. Если время ожидания вызова истекает, полученный элемент System.Threading.Tasks завершается с исключением OperationCanceledException. Перехватите и обработайте исключение с ведением журнала.

Аналогичным образом код JavaScript может инициировать вызовы методов .NET, указанных в атрибуте [JSInvokable] . Если эти методы .NET создают необработанное исключение:

  • исключение не рассматривается как неустранимое для канала Blazor Server;
  • Promise на стороне JavaScript отклоняется.

Вы можете использовать код обработки ошибок либо на стороне .NET, либо на стороне JavaScript вызова метода.

Дополнительные сведения см. в следующих статьях:

Предварительная отрисовка (Blazor Server)

Компоненты Razor можно предварительно отрисовать с помощью вспомогательной функции тега компонента, чтобы их отрисованная разметка HTML возвращалась как часть исходного HTTP-запроса пользователя. Это происходит следующим образом:

  • Создается новый канал для всех предварительно отрисованных компонентов, которые являются частью одной страницы.
  • Создается исходный HTML-код.
  • Канал рассматривается как disconnected , пока браузер пользователя не установит подключение SignalR к тому же серверу. Если соединение установлено, взаимодействие с каналом возобновляется, а HTML-разметка компонентов обновляется.

Если какой-либо компонент создает необработанное исключение во время предварительной отрисовки, например во время метода жизненного цикла или в логике отрисовки:

  • Исключение является неустранимым для канала.
  • Исключение вызывается в стеке вызовов из вспомогательной функции тега ComponentTagHelper. Таким образом, весь HTTP-запрос завершается ошибкой, если только исключение явно не перехвачено кодом разработчика.

В обычных обстоятельствах при сбое предварительной отрисовки продолжение сборки и отрисовки компонента не имеет смысла, так как невозможно отрисовать рабочий компонент.

Чтобы допускать ошибки, которые могут возникнуть во время предварительной отрисовки, логика обработки ошибок должна размещаться внутри компонента, который может вызывать исключения. Используйте инструкции try-catch с обработкой ошибок и ведением журнала. Вместо того чтобы упаковывать вспомогательную функцию тега ComponentTagHelper в инструкцию try-catch , поместите логику обработки ошибок в компонент, отрисовываемый вспомогательной функцией тега ComponentTagHelper.

Сложные сценарии

Рекурсивная отрисовка

Компоненты можно вкладывать друг в друга рекурсивно. Это полезно для представления рекурсивных структур данных. Например, компонент TreeNode может отрисовывать другие компоненты TreeNode для каждого из дочерних элементов узла.

При рекурсивной отрисовке избегайте шаблонов кодирования, которые приводят к бесконечной рекурсии:

  • Не следует рекурсивно отрисовывать структуру данных, содержащую цикл. Например, не следует отрисовывать узел дерева, дочерние элементы которого содержат сами себя.
  • Не создавайте цепочку макетов, содержащих цикл. Например, не создавайте макет, макетом которого является он сам.
  • Не разрешайте пользователю нарушать инварианты рекурсии (правила) с помощью ввода вредоносных данных или вызовов взаимодействия JavaScript.

Бесконечные циклы во время отрисовки:

  • Приводят к тому, что процесс отрисовки будет выполняться бесконечно.
  • Эквивалентны созданию незавершенного цикла.

В этих сценариях происходит сбой потока Blazor WebAssembly или канала Blazor Server, и поток или канал обычно пытается выполнить следующие действия:

  • Использовать столько процессорных ресурсов, сколько разрешено операционной системой, в неограниченном объеме.
  • Использовать неограниченный объем памяти. Использование неограниченного объема памяти эквивалентно сценарию, в котором незавершенный цикл добавляет записи в коллекцию при каждой итерации.

Чтобы избежать бесконечного шаблона рекурсии, убедитесь, что рекурсивный код отрисовки содержит подходящие условия остановки.

Пользовательская логика дерева отрисовки

Большинство компонентов Razor реализуются как файлы компонента Razor ( .razor ) и компилируются платформой для создания логики, которая работает в RenderTreeBuilder для отрисовки выходных данных. Разработчик может вручную реализовать логику RenderTreeBuilder с помощью процедурного кода C#. Дополнительные сведения см. в разделе «Расширенные сценарии ASP.NET Core Blazor (построение дерева визуализации)».

Использование выполняемой вручную логики построителя дерева считается сложным и небезопасным сценарием, не рекомендуемым для обычной разработки компонентов.

При написании кода RenderTreeBuilder разработчик должен гарантировать правильность кода. Например, разработчик должен убедиться в том, что:

  • Вызовы к OpenElement и CloseElement правильно сбалансированы.
  • Атрибуты добавляются только в нужные места.

Неправильная логика конструктора выполняемой вручную логики построителя дерева отрисовки может вызвать произвольное неопределенное поведение, включая сбои, зависания приложения (Blazor WebAssembly) или сервера (Blazor Server) и уязвимости системы безопасности.

Считайте, что выполняемая вручную логика построителя дерева отрисовки имеет тот же уровень сложности и опасности, что и написание кода сборки или инструкций MSIL вручную.

Дополнительные ресурсы

Blazor WebAssembly

†Применяется к серверным веб-API ASP.NET Core, которые клиентские приложения Blazor WebAssembly используют для ведения журнала.

Blazor Server

†Применяется к приложениям ASP.NET Core на стороне сервера, которые являются серверными приложениями веб-API для приложений Blazor.

Подробные сведения об ошибках во время разработки приложений Blazor WebAssembly

Если во время разработки приложение Blazor работает неправильно, подробные сведения об ошибках в приложении могут помочь в устранении неполадок. При возникновении ошибки в приложении Blazor в нижней части экрана отображается светло-желтая полоса:

  • Во время разработки из этой полосы можно перейти в консоль браузера, где можно просмотреть исключение.
  • В рабочей среде эта полоса уведомляет пользователя о том, что произошла ошибка, и рекомендует обновить содержимое окна браузера.

Пользовательский интерфейс для этого процесса обработки ошибок входит в состав шаблонов проектов Blazor.

В приложении Blazor WebAssembly настройте интерфейс в файле wwwroot/index.html :

Элемент blazor-error-ui обычно скрыт из-за наличия стиля display: none класса CSS blazor-error-ui в таблице стилей приложения ( wwwroot/css/app.css ). При возникновении ошибки платформа применяет display: block к элементу.

Управление необработанными исключениями в коде разработчика

Чтобы приложение продолжало работу после возникновения ошибки, в нем должна быть логика обработки ошибок. В последующих разделах этой статьи описываются потенциальные источники необработанных исключений.

В рабочей среде не следует отображать сообщения об исключениях платформы или трассировки стека в пользовательском интерфейсе. Отображение сообщений об исключениях или трассировок стека может:

  • Раскрыть конфиденциальные сведения конечным пользователям.
  • Помочь злоумышленнику обнаружить слабые места в приложении, что может нарушить безопасность приложения, сервера или сети.

Глобальная обработка исключений

Blazor — это клиентская платформа одностраничного приложения (SPA). Браузер служит узлом приложения и, таким образом, действует как конвейер обработки для отдельных компонентов Razor на основе запросов URI для навигации и статических ресурсов. В отличие от приложений ASP.NET Core, которые работают на сервере с конвейером обработки ПО промежуточного слоя, конвейера ПО промежуточного слоя, обрабатывающего запросы компонентов Razor, которые можно использовать для глобальной обработки ошибок, не существует. Однако в качестве каскадного значения для централизованной обработки ошибок приложение может использовать компонент обработки ошибок.

Следующий компонент Error передает себя дочерним компонентам в качестве CascadingValue . В следующем примере просто регистрируется ошибка, но методы компонента могут обрабатывать ошибки любым способом, требуемым для приложения, в том числе с использованием нескольких методов обработки ошибок. Преимущество использования компонента по сравнению с использованием внедренной службы или реализации пользовательского средства ведения журнала заключается в том, что при возникновении ошибки каскадный компонент может отрисовывать содержимое и применять стили CSS.

В компоненте App создайте программу-оболочку для компонента Router с помощью компонента Error . Благодаря этому компонент Error сможет переходить к любому компоненту приложения, в котором компонент Error получен как CascadingParameter .

Чтобы обработать ошибки в компоненте, выполните приведенные ниже действия.

Назначьте компонент Error как CascadingParameter в блоке @code :

Вызовите метод обработки ошибок в любом блоке catch с соответствующим типом исключения. В примере компонента Error есть только один метод ProcessError . Однако компонент обработки ошибок может предоставить любое количество соответствующих методов, чтобы удовлетворить альтернативные требования к обработке ошибок во всем приложении.

Используя компонент Error и метод ProcessError из предыдущего примера, консоль инструментов разработчика обозревателя указывает на перехваченную, зарегистрированную ошибку:

Сбой: BlazorSample.Shared.Error[0] Error:ProcessError — Тип: System.NullReferenceException Сообщение: Ссылка на объект не указывает на экземпляр объекта.

Если метод ProcessError напрямую участвует в отрисовке, например показывает пользовательскую панель сообщений об ошибках или изменяет стили CSS отрисованных элементов, вызовите StateHasChanged в конце метода ProcessErrors для повторной отрисовки пользовательского интерфейса.

Так как подходы в этом разделе предусматривают обработку ошибок с помощью инструкции try-catch , соединение SignalR приложения Blazor Server между клиентом и сервером не прерывается при возникновении ошибки и канал остается активным. Необработанное исключение является неустранимым для канала. Дополнительные сведения о том, как приложение Blazor Server реагирует на необработанные исключения,.

Регистрация ошибок с помощью постоянного поставщика (Blazor WebAssembly)

При возникновении необработанного исключения оно заносится в журнал экземпляров ILogger, настроенных в контейнере службы. По умолчанию приложения Blazor записываются в выходные данные консоли с помощью поставщика ведения журнала консоли. Возможно, следует сохранять записи журнала в более постоянное расположение на сервере, отправляя сведения об ошибке в серверный веб-API, который использует поставщик ведения журнала с возможностью управления размером журнала и ротации журналов. Кроме того, серверное приложение веб-API может использовать службу управления производительностью приложений (APM), например Azure Application Insights (Azure Monitor)†, для записи сведений об ошибках, получаемых от клиентов.

Необходимо решить, какие инциденты следует заносить в журнал, и выбрать уровень серьезности регистрируемых инцидентов. Злоумышленники могут попытаться вызывать ошибки намеренно. Например, не заносите в журнал инцидент в результате ошибки, когда в URL-адресе компонента, отображающего сведения о продукте, указан неизвестный ProductId . Не все ошибки следует рассматривать как инциденты, подлежащие записи в журнал.

Дополнительные сведения см. в следующих статьях:

†Встроенные возможности Application Insights для поддержки приложений Blazor WebAssembly и поддержки собственной платформы Blazor для Google Analytics могут стать доступными в будущих выпусках этих технологических решений. Дополнительные сведения см. в статьях Поддержка App Insights на стороне клиента Blazor WASM (microsoft/ApplicationInsights-dotnet #2143) и Веб-аналитика и диагностика (содержит ссылки на реализации сообщества) (dotnet/aspnetcore #5461). В то же время приложение Blazor WebAssembly на стороне клиента может использовать пакет SDK JavaScript Application Insights и взаимодействие JS для записи ошибок непосредственно в Application Insights из клиентского приложения.

‡Применяется к приложениям ASP.NET Core на стороне сервера, которые являются серверными приложениями веб-API для приложений Blazor. Приложения на стороне клиента регистрируют и отправляют сведения об ошибках в веб-API, который регистрирует сведения об ошибке в постоянном поставщике ведения журнала.

Места в приложениях Blazor WebAssembly, где могут появляться ошибки

Код платформы и приложения может активировать необработанные исключения в любом из следующих расположений, которые описаны в следующих разделах этой статьи.

Экземпляр компонента (Blazor WebAssembly)

Когда Blazor создает экземпляр компонента:

  • Вызывается конструктор компонента.
  • Вызываются конструкторы любых не отдельных служб DI, которые передаются в конструктор компонента с помощью директивы @inject или атрибута [Inject] .

Ошибка в выполненном конструкторе или методе задания для любого свойства [Inject] приводит к возникновению необработанного исключения и предотвращает создание экземпляра компонента на платформе. Если логика конструктора может вызывать исключения, приложение должно выполнить перехват исключений с помощью инструкции try-catch с обработкой ошибок и ведением журнала.

Методы жизненного цикла (Blazor WebAssembly)

В течение времени существования компонента Blazor вызывает методы жизненного цикла. Для компонентов, обрабатывающих ошибки в методах жизненного цикла, добавьте логику обработки ошибок.

В следующем примере OnParametersSetAsync вызывает метод для получения продукта:

  • Исключение, вызванное в методе ProductRepository.GetProductByIdAsync , обрабатывается оператором try-catch .
  • При выполнении блока catch :
    • loadFailed получает значение true , которое используется для вывода сообщения об ошибке пользователю.
    • Ошибка регистрируется в журнале.

Логика отрисовки (Blazor WebAssembly)

Декларативная разметка в файле компонента Razor ( .razor ) компилируется в метод C# с именем BuildRenderTree. Когда компонент отрисовывается, BuildRenderTree выполняет и создает структуру данных, описывающую элементы, текст и дочерние компоненты отрисованного компонента.

Логика отрисовки может вызывать исключение. Пример этого сценария происходит, когда @someObject.PropertyName вычисляется, но @someObject имеет значение null .

Чтобы предотвратить NullReferenceException в логике отрисовки, проверьте наличие объекта null перед обращением к его элементам. В следующем примере свойства person.Address недоступны, если person.Address имеет значение null :

В приведенном выше коде предполагается, что person не имеет значение null . Часто структура кода гарантирует, что объект существует на момент отрисовки компонента. В таких случаях нет необходимости проверять наличие null в логике отрисовки. В предыдущем примере person может гарантированно существовать, так как person создается при создании экземпляра компонента, как показано в следующем примере:

Обработчики событий (Blazor WebAssembly)

Код на стороне клиента активирует вызовы кода C# при создании обработчиков событий с помощью:

В этих сценариях код обработчика событий может вызывать необработанное исключение.

Если приложение вызывает код, который может завершиться ошибкой по внешним причинам, перехватите исключения с помощью инструкции try-catch с обработкой ошибок и ведением журнала.

Если пользовательский код не выполняет перехват и обработку исключения, платформа регистрирует исключение.

Удаление компонентов (Blazor WebAssembly)

Компонент может быть удален из пользовательского интерфейса, например, потому, что пользователь перешел на другую страницу. Когда компонент, реализующий System.IDisposable, удаляется из пользовательского интерфейса, платформа вызывает метод Dispose компонента.

Если логика удаления может вызывать исключения, приложение должно выполнить перехват исключений с помощью инструкции try-catch с обработкой ошибок и ведением журнала.

Дополнительные сведения об удалении компонентов см. в разделе Жизненный цикл компонента RazorASP.NET Core.

Взаимодействие с JavaScript (Blazor WebAssembly)

IJSRuntime регистрируется платформой Blazor. IJSRuntime.InvokeAsync позволяет коду .NET выполнять асинхронные вызовы в среде выполнения JavaScript в браузере пользователя.

К обработке ошибок с помощью InvokeAsync применяются следующие условия:

  • Если вызов к InvokeAsync выполняется синхронно, возникает исключение .NET. Вызов к InvokeAsync может завершиться ошибкой, например, поскольку передаваемые аргументы не могут быть сериализованы. Код разработчика должен перехватить исключение.
  • Если вызов InvokeAsync асинхронно завершается сбоем, .NET Task также завершается сбоем. Вызов к InvokeAsync может завершиться ошибкой, например, потому, что код на стороне JavaScript вызывает исключение или возвращает Promise , который был завершен как rejected . Код разработчика должен перехватить исключение. При использовании оператора await рекомендуется заключить вызов метода в инструкцию try-catch с обработкой ошибок и ведением журнала.
  • По умолчанию вызовы к InvokeAsync должны завершаться в течение определенного периода или время ожидания вызова истекает. Период ожидания по умолчанию составляет одну минуту. Время ожидания защищает код от потери сетевого подключения или кода JavaScript, который никогда не отправляет обратно сообщение о завершении. Если время ожидания вызова истекает, полученный элемент System.Threading.Tasks завершается с исключением OperationCanceledException. Перехватите и обработайте исключение с ведением журнала.

Аналогичным образом код JavaScript может инициировать вызовы методов .NET, указанных в атрибуте [JSInvokable] . Если эти методы .NET создают необработанное исключение, то Promise на стороне JavaScript отклоняется.

Вы можете использовать код обработки ошибок либо на стороне .NET, либо на стороне JavaScript вызова метода.

Дополнительные сведения см. в следующих статьях:

Подробные сведения об ошибках во время разработки приложений Blazor Server

Если во время разработки приложение Blazor работает неправильно, подробные сведения об ошибках в приложении могут помочь в устранении неполадок. При возникновении ошибки в приложении Blazor в нижней части экрана отображается светло-желтая полоса:

  • Во время разработки из этой полосы можно перейти в консоль браузера, где можно просмотреть исключение.
  • В рабочей среде эта полоса уведомляет пользователя о том, что произошла ошибка, и рекомендует обновить содержимое окна браузера.

Пользовательский интерфейс для этого процесса обработки ошибок входит в состав шаблонов проектов Blazor.

В приложении Blazor Server настройте интерфейс в файле Pages/_Host.cshtml :

Элемент blazor-error-ui обычно скрыт из-за наличия стиля display: none класса CSS blazor-error-ui в таблице стилей сайта ( wwwroot/css/site.css ). При возникновении ошибки платформа применяет display: block к элементу.

Подробное описание ошибок каналов в Blazor Server

Ошибки на стороне клиента не включают сведения о стеке вызовов и не предоставляют сведения о причине ошибки, но журналы сервера содержат эти сведения. В целях разработки конфиденциальные сведения об ошибках каналов можно сделать доступными для клиента, включив подробное описание ошибок.

Задайте для параметра CircuitOptions.DetailedErrors значение true . Дополнительные сведения и пример см. в разделе Руководство поBlazorSignalR ASP.NET Core .

В качестве альтернативы заданию параметра CircuitOptions.DetailedErrors можно задать для ключа конфигурации DetailedErrors значение true в файле параметров окружения разработки приложения ( appsettings.Development.json ). Кроме того, задайте для параметра SignalRведения журнала на стороне сервера ( Microsoft.AspNetCore.SignalR ) значение Отладка или Трассировка, чтобы обеспечить подробное ведение журнала SignalR.

Можно также задать DetailedErrors значение true для ключа конфигурации, используя переменную окружения ASPNETCORE_DETAILEDERRORS со значением true на серверах окружения разработки и промежуточной среды или в локальной системе.

Никогда не предоставляйте сведения об ошибках клиентам в Интернете, так как это подвергает безопасность угрозе.

Как приложение Blazor Server реагирует на необработанные исключения

Blazor Server — это платформа с отслеживанием состояния. Когда пользователи взаимодействуют с приложением, они поддерживают подключение к серверу, которое называется каналом. Канал содержит экземпляры активных компонентов, а также многие другие аспекты состояния, например:

  • Последние отображаемые выходные данные компонентов.
  • Текущий набор делегатов обработки событий, которые могут вызываться событиями на стороне клиента.

Если пользователь открывает приложение на нескольких вкладках браузера, он создает несколько независимых каналов.

Blazor обрабатывает большинство необработанных исключений как неустранимые для канала, где они происходят. Если канал завершается из-за необработанного исключения, пользователь может продолжить взаимодействие с приложением только путем перезагрузки страницы для создания нового канала. Это не влияет на остальные каналы для других пользователей или других вкладок браузера. Этот сценарий аналогичен сценарию с настольным приложением, которое аварийно завершает работу. Такое приложение необходимо перезапустить, но остальные приложения это не затрагивает.

Платформа завершает канал при возникновении необработанного исключения по следующим причинам:

  • Необработанное исключение часто оставляет канал в неопределенном состоянии.
  • После необработанного исключения нормальную работу приложения невозможно гарантировать.
  • Дальнейшая работа канала в неопределенном состоянии может стать причиной уязвимостей системы безопасности.

Регистрация ошибок с помощью постоянного поставщика (Blazor Server)

При возникновении необработанного исключения оно заносится в журнал экземпляров ILogger, настроенных в контейнере службы. По умолчанию приложения Blazor записываются в выходные данные консоли с помощью поставщика ведения журнала консоли. Возможно, следует сохранять записи журнала в более постоянное расположение на сервере с помощью поставщика, который управляет размером журнала и их ротацией. Кроме того, приложение может использовать службу управления производительностью приложений (APM), например Azure Application Insights (Azure Monitor).

Во время разработки приложение Blazor Server обычно отправляет полные сведения об исключениях в консоль браузера для поддержки отладки. В рабочей среде подробные сообщения об ошибках не отправляются клиентам, но все сведения об исключениях записываются на сервер.

Необходимо решить, какие инциденты следует заносить в журнал, и выбрать уровень серьезности регистрируемых инцидентов. Злоумышленники могут попытаться вызывать ошибки намеренно. Например, не заносите в журнал инцидент в результате ошибки, когда в URL-адресе компонента, отображающего сведения о продукте, указан неизвестный ProductId . Не все ошибки следует рассматривать как инциденты, подлежащие записи в журнал.

Дополнительные сведения см. в следующих статьях:

†Применяется к приложениям ASP.NET Core на стороне сервера, которые являются серверными приложениями веб-API для приложений Blazor.

Места в приложениях Blazor Server, где могут появляться ошибки

Код платформы и приложения может активировать необработанные исключения в любом из следующих расположений, которые описаны в следующих разделах этой статьи.

Экземпляр компонента (Blazor Server)

Когда Blazor создает экземпляр компонента:

  • Вызывается конструктор компонента.
  • Вызываются конструкторы любых не отдельных служб DI, которые передаются в конструктор компонента с помощью директивы @inject или атрибута [Inject] .

Сбой канала Blazor Server происходит, когда любой выполненный конструктор или метод задания для любого свойства [Inject] выдает необработанное исключение. Исключение является неустранимым, так как платформе не удается создать экземпляр компонента. Если логика конструктора может вызывать исключения, приложение должно выполнить перехват исключений с помощью инструкции try-catch с обработкой ошибок и ведением журнала.

Методы жизненного цикла (Blazor Server)

В течение времени существования компонента Blazor вызывает методы жизненного цикла. Если какой-либо метод жизненного цикла вызывает исключение (синхронно или асинхронно), такое исключение является неустранимым для канала Blazor Server. Для компонентов, обрабатывающих ошибки в методах жизненного цикла, добавьте логику обработки ошибок.

В следующем примере OnParametersSetAsync вызывает метод для получения продукта:

  • Исключение, вызванное в методе ProductRepository.GetProductByIdAsync , обрабатывается оператором try-catch .
  • При выполнении блока catch :
    • loadFailed получает значение true , которое используется для вывода сообщения об ошибке пользователю.
    • Ошибка регистрируется в журнале.

Логика отрисовки (Blazor Server)

Декларативная разметка в файле компонента Razor ( .razor ) компилируется в метод C# с именем BuildRenderTree. Когда компонент отрисовывается, BuildRenderTree выполняет и создает структуру данных, описывающую элементы, текст и дочерние компоненты отрисованного компонента.

Логика отрисовки может вызывать исключение. Пример этого сценария происходит, когда @someObject.PropertyName вычисляется, но @someObject имеет значение null . Необработанное исключение, созданное логикой отрисовки, является неустранимым для канала Blazor Server.

Чтобы предотвратить NullReferenceException в логике отрисовки, проверьте наличие объекта null перед обращением к его элементам. В следующем примере свойства person.Address недоступны, если person.Address имеет значение null :

В приведенном выше коде предполагается, что person не имеет значение null . Часто структура кода гарантирует, что объект существует на момент отрисовки компонента. В таких случаях нет необходимости проверять наличие null в логике отрисовки. В предыдущем примере person может гарантированно существовать, так как person создается при создании экземпляра компонента, как показано в следующем примере:

Обработчики событий (Blazor Server)

Код на стороне клиента активирует вызовы кода C# при создании обработчиков событий с помощью:

В этих сценариях код обработчика событий может вызывать необработанное исключение.

Если обработчик событий создает необработанное исключение (например, запрос к базе данных завершается ошибкой), такое исключение является неустранимым для канала Blazor Server. Если приложение вызывает код, который может завершиться ошибкой по внешним причинам, перехватите исключения с помощью инструкции try-catch с обработкой ошибок и ведением журнала.

Если пользовательский код не выполняет перехват и обработку исключения, платформа регистрирует исключение и завершает канал.

Удаление компонентов (Blazor Server)

Компонент может быть удален из пользовательского интерфейса, например, потому, что пользователь перешел на другую страницу. Когда компонент, реализующий System.IDisposable, удаляется из пользовательского интерфейса, платформа вызывает метод Dispose компонента.

Если метод Dispose компонента создает необработанное исключение, такое исключение является неустранимым для канала Blazor Server. Если логика удаления может вызывать исключения, приложение должно выполнить перехват исключений с помощью инструкции try-catch с обработкой ошибок и ведением журнала.

Дополнительные сведения об удалении компонентов см. в разделе Жизненный цикл компонента RazorASP.NET Core.

Взаимодействие с JavaScript (Blazor Server)

IJSRuntime регистрируется платформой Blazor. IJSRuntime.InvokeAsync позволяет коду .NET выполнять асинхронные вызовы в среде выполнения JavaScript в браузере пользователя.

К обработке ошибок с помощью InvokeAsync применяются следующие условия:

  • Если вызов к InvokeAsync выполняется синхронно, возникает исключение .NET. Вызов к InvokeAsync может завершиться ошибкой, например, поскольку передаваемые аргументы не могут быть сериализованы. Код разработчика должен перехватить исключение. Если код приложения в обработчике событий или методе жизненного цикла компонента не обрабатывает исключение, полученное исключение является неустранимым для канала Blazor Server.
  • Если вызов InvokeAsync асинхронно завершается сбоем, .NET Task также завершается сбоем. Вызов к InvokeAsync может завершиться ошибкой, например, потому, что код на стороне JavaScript вызывает исключение или возвращает Promise , который был завершен как rejected . Код разработчика должен перехватить исключение. При использовании оператора await рекомендуется заключить вызов метода в инструкцию try-catch с обработкой ошибок и ведением журнала. В противном случае сбой кода приводит к возникновению необработанного исключения, которое является неустранимым для канала Blazor Server.
  • По умолчанию вызовы к InvokeAsync должны завершаться в течение определенного периода или время ожидания вызова истекает. Период ожидания по умолчанию составляет одну минуту. Время ожидания защищает код от потери сетевого подключения или кода JavaScript, который никогда не отправляет обратно сообщение о завершении. Если время ожидания вызова истекает, полученный элемент System.Threading.Tasks завершается с исключением OperationCanceledException. Перехватите и обработайте исключение с ведением журнала.

Аналогичным образом код JavaScript может инициировать вызовы методов .NET, указанных в атрибуте [JSInvokable] . Если эти методы .NET создают необработанное исключение:

  • исключение не рассматривается как неустранимое для канала Blazor Server;
  • Promise на стороне JavaScript отклоняется.

Вы можете использовать код обработки ошибок либо на стороне .NET, либо на стороне JavaScript вызова метода.

Дополнительные сведения см. в следующих статьях:

Предварительная отрисовка (Blazor Server)

Компоненты Razor можно предварительно отрисовать с помощью вспомогательной функции тега компонента, чтобы их отрисованная разметка HTML возвращалась как часть исходного HTTP-запроса пользователя. Это происходит следующим образом:

  • Создается новый канал для всех предварительно отрисованных компонентов, которые являются частью одной страницы.
  • Создается исходный HTML-код.
  • Канал рассматривается как disconnected , пока браузер пользователя не установит подключение SignalR к тому же серверу. Если соединение установлено, взаимодействие с каналом возобновляется, а HTML-разметка компонентов обновляется.

Если какой-либо компонент создает необработанное исключение во время предварительной отрисовки, например во время метода жизненного цикла или в логике отрисовки:

  • Исключение является неустранимым для канала.
  • Исключение вызывается в стеке вызовов из вспомогательной функции тега ComponentTagHelper. Таким образом, весь HTTP-запрос завершается ошибкой, если только исключение явно не перехвачено кодом разработчика.

В обычных обстоятельствах при сбое предварительной отрисовки продолжение сборки и отрисовки компонента не имеет смысла, так как невозможно отрисовать рабочий компонент.

Чтобы допускать ошибки, которые могут возникнуть во время предварительной отрисовки, логика обработки ошибок должна размещаться внутри компонента, который может вызывать исключения. Используйте инструкции try-catch с обработкой ошибок и ведением журнала. Вместо того чтобы упаковывать вспомогательную функцию тега ComponentTagHelper в инструкцию try-catch , поместите логику обработки ошибок в компонент, отрисовываемый вспомогательной функцией тега ComponentTagHelper.

Сложные сценарии

Рекурсивная отрисовка

Компоненты можно вкладывать друг в друга рекурсивно. Это полезно для представления рекурсивных структур данных. Например, компонент TreeNode может отрисовывать другие компоненты TreeNode для каждого из дочерних элементов узла.

При рекурсивной отрисовке избегайте шаблонов кодирования, которые приводят к бесконечной рекурсии:

  • Не следует рекурсивно отрисовывать структуру данных, содержащую цикл. Например, не следует отрисовывать узел дерева, дочерние элементы которого содержат сами себя.
  • Не создавайте цепочку макетов, содержащих цикл. Например, не создавайте макет, макетом которого является он сам.
  • Не разрешайте пользователю нарушать инварианты рекурсии (правила) с помощью ввода вредоносных данных или вызовов взаимодействия JavaScript.

Бесконечные циклы во время отрисовки:

  • Приводят к тому, что процесс отрисовки будет выполняться бесконечно.
  • Эквивалентны созданию незавершенного цикла.

В этих сценариях происходит сбой потока Blazor WebAssembly или канала Blazor Server, и поток или канал обычно пытается выполнить следующие действия:

  • Использовать столько процессорных ресурсов, сколько разрешено операционной системой, в неограниченном объеме.
  • Использовать неограниченный объем памяти. Использование неограниченного объема памяти эквивалентно сценарию, в котором незавершенный цикл добавляет записи в коллекцию при каждой итерации.

Чтобы избежать бесконечного шаблона рекурсии, убедитесь, что рекурсивный код отрисовки содержит подходящие условия остановки.

Пользовательская логика дерева отрисовки

Большинство компонентов Razor реализуются как файлы компонента Razor ( .razor ) и компилируются платформой для создания логики, которая работает в RenderTreeBuilder для отрисовки выходных данных. Разработчик может вручную реализовать логику RenderTreeBuilder с помощью процедурного кода C#. Дополнительные сведения см. в разделе «Расширенные сценарии ASP.NET Core Blazor (построение дерева визуализации)».

Использование выполняемой вручную логики построителя дерева считается сложным и небезопасным сценарием, не рекомендуемым для обычной разработки компонентов.

При написании кода RenderTreeBuilder разработчик должен гарантировать правильность кода. Например, разработчик должен убедиться в том, что:

  • Вызовы к OpenElement и CloseElement правильно сбалансированы.
  • Атрибуты добавляются только в нужные места.

Неправильная логика конструктора выполняемой вручную логики построителя дерева отрисовки может вызвать произвольное неопределенное поведение, включая сбои, зависания приложения (Blazor WebAssembly) или сервера (Blazor Server) и уязвимости системы безопасности.

Считайте, что выполняемая вручную логика построителя дерева отрисовки имеет тот же уровень сложности и опасности, что и написание кода сборки или инструкций MSIL вручную.

Источник

Читайте также:  1cv8c exe ошибка приложения исключение unknown software exception
Оцените статью
toolgir.ru
Adblock
detector