An unhandled error has occurred reload blazor



Problem AND Solution: Default Example Blazor WebAssembly Solution fails to Load the FetchData page with error message «An unhandled error has occurred. Reload» #21698

Comments

vsfeedback commented May 11, 2020

Problem: Default Example Blazor WebAssembly Solution may (or may not) fail to Load on FetchData page with error message «An unhandled error has occurred. Reload»

Problem is easily recreatable and easily fixed.

When you create a brand new C# Blazor WebAssembly solution, the default example that is created contains one solution with three projects:

(Where [BlazorSolutionName] is the name you choose when creating the solution)

  • Solution [BlazorSolutionName]
    • [BlazorSolutionName]. Client
    • [BlazorSolutionName]. Server
    • [BlazorSolutionName]. Shared

To Recreate Problem:

  1. Install Visiual Studio Version 16.6.0 Preview 6.0 and Blazor WebAssembly 3.2.0 Preview 5
    • Instructions available at: https://devblogs.microsoft.com/aspnet/blazor-webassembly-3-2-0-preview-5-release-now-available/
  2. Create a new Blazor App\Blazor WebAssembly App with «Configure for HTTPS» and «ASP.NET Core Hosted» both checked on.
  3. Visual Studio will build an example solution by default.
    • Side note: Wish there was a radio button option when creating the solution to make an empty solution and projects.
  4. Select Build\Rebuild Solution just to be sure entire solution builds successfully.
  5. BEFORE running solution, single click on [BlazorSolutionName]. Client so it is bolded\highlighted. Make sure it stays bold\highlighted.
  6. Now run the solution.
  7. You should see the sample solution load in the browser with «Home», «Counter», and «Fetch data» buttons on left side.
  8. Click «Fetch data» and see that it doesn’t load and gives error message at very bottom of page.
  9. Close the browser to stop the application.
  10. Now, single click on [BlazorSolutionName]. Server just so it is bolded\highlighted.
  11. Now rerun the app and click on «Fetch data» and see that it runs successfully.

When you run the solution, it «might» fail on the FetchData page with an error message «An unhandled error has occurred. Reload» at times and then not at other times depending on which project you have bolded\highlighted.

Reason Occurs:
This error occurs when the default project for the solution is anything but «[YourSolutionName]. Server». You may see it some times and not other times depending on which project (client, server, or shared) you have highlighted when you run the solution. This is because the example solution is installled with the default project set to «Current Selection». The default project should be changed to: «[YourSolutionName]. Server»

Steps to Fix:

  1. Right click on the Solution in Visual Studio
  2. Select «Properties»
  3. Change Radio Button selection «Current Selection» to «Single Startup Project»
  4. Under «Single Startup Project» select [YourSolutionName]. Server
  5. Click «Apply»
  6. Click «OK»
  7. Just to be sure, save all files and then rebuild project.
  8. Now FetchData page should work at all times.
  9. If still having problems reboot and re-try steps above.

Microsoft Visual Studio Community 2019 Preview
Version 16.6.0 Preview 6.0
Blazor WebAssembly 3.2.0 Preview 5
Microsoft .NET Framework — Version 4.8.03752

Hope this helps.

Original Comments

Visual Studio Feedback System on 5/10/2020, 10:37 PM:

We have directed your feedback to the appropriate engineering team for further evaluation. The team will review the feedback and notify you about the next steps.

Original Solutions

toddalbers solved on 5/10/2020, 08:34 AM, 0 votes:

Solution is provided in problem description above already.

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

Источник

Обработка ошибок в приложениях 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 правильно сбалансированы.
  • Атрибуты добавляются только в нужные места.
Читайте также:  Steam exe main exception что это

Неправильная логика конструктора выполняемой вручную логики построителя дерева отрисовки может вызвать произвольное неопределенное поведение, включая сбои, зависания приложения (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 . Однако компонент обработки ошибок может предоставить любое количество соответствующих методов, чтобы удовлетворить альтернативные требования к обработке ошибок во всем приложении.

Читайте также:  Gpstart error master instance process running

Используя компонент 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 к элементу.

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

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

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

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

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

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 вручную.

Источник

Оцените статью
toolgir.ru
Adblock
detector