Содержание
Когда в приложении Blazor возникает какое-либо исключение, то, по умолчанию, это приводит к тому, что работа приложения полностью останавливается, а пользователь видит внизу экрана сообщение о том, что произошло необрабатываемое исключение. Сегодня разберемся с тем, как можно организовать обработку исключений в Blazor, используя возможности .NET 6.
Пример Blazor Server с ошибкой
Допустим, что у нас есть в приложении такой компонент счётчика:
@page "/counter" @using System <PageTitle>Counter</PageTitle> <h1>Counter</h1> <p role="status">Current count: @currentCount</p> <button class="btn btn-primary" @onclick="IncrementCount">Click me</button> @code { private int currentCount = 0; private void IncrementCount() { currentCount++; if (currentCount > 5) throw new Exception("Ошибка счётчика"); } }
Как только значение счётчика превышает значение 5 — возникает исключение. В работающем приложении это будет выглядеть следующим образом:
Находясь в режиме разработки, мы можем открыть панель разработчика в браузере и изучить детали ошибки или же открыть консоль и увидеть детали:
При этом, приложение игнорирует дальнейшие действия пользователя до тех пор, пока он не кликнет по ссылке Reload. Сам текст ошибки, который видит пользователь, находится в файле _Layout.cshtml, который компонентом Blazor не является. При этом, не всегда ошибки в приложении являются фатальными, из-за которых требуется полностью останавливать выполнение приложение. В приведенном примере нам было бы достаточно сообщить пользователю об ошибке в компоненте и продолжить работу. В .NET 6 мы можем организовать такую работу, благодаря компоненту ErrorBoundary
.
Компонент Blazor ErrorBoundary
Компонент Blazor ErrorBoundary
позволяет локализовать исключение в месте его возникновения и, при этом, останавливать работу всего приложения. Добавим ErrorBoundary в наш проект. Для этого внесем в компонент MainLayout.razor следующий код:
@inherits LayoutComponentBase <PageTitle>BlazorBootstrap</PageTitle> <div class="page"> <div class="sidebar"> <NavMenu /> </div> <main> <article class="content px-4"> <ErrorBoundary> @Body </ErrorBoundary> </article> </main> </div>
Здесь мы «обернули» элемент Body в ErrorBoundary
, указав, тем самым границы ошибок. Теперь запустим приложение, перейдем на страницу счётчика и попробуем его нарастить до возникновения ошибки. На шестом клике по кнопке мы увидим следующее сообщение:
Во-первых, сообщение об ошибке выведено в том месте, где возникло исключение. Во-вторых, приложение продолжает работать — мы можем спокойно уйти со страницы счётчика на любую другую страницу без перезагрузки приложения. В-третьих, изменился стиль отображения сообщения об ошибке.
Мы можем использовать ErrorBoundary
не только в MainLayout.razor, но и в любых других местах приложения, где могут возникать не критические ошибки, которые не нарушают в целом работоспособность приложения. Например, иы могли бы использовать ErrorBoundary
на главной странице:
@page "/" <PageTitle>Index</PageTitle> <h1>Hello, world! </h1> Welcome to your new app. <SurveyPrompt Title="How is Blazor working for you?" /> <ErrorBoundary> <Counter></Counter> </ErrorBoundary>
В этом случае, ошибка счётчика выглядела бы следующим образом:
Опять же, как видите, сообщение об ошибке появилось в месте расположения счётчика, не затронув при этом другие компоненты страницы.
Свойства ErrorBoundary
Не всегда удобно отображать сообщение об ошибке по умолчанию. Может потребоваться изменить текст ошибки или стиль отображения элемента, чтобы оно наиболее полно соответствовало стили вашего приложения. ErrorBoundary
позволяет выполнить такие изменения. Например, отобразим сообщение об ошибке в компоненте Bootstrap alert
:
<ErrorBoundary> <ChildContent> <Counter /> </ChildContent> <ErrorContent> <div class="alert alert-danger" role="alert"> Произошла ошибка в компоненте Counter </div> </ErrorContent> </ErrorBoundary>
Здесь ChildContent
— это содержимое, отображаемое при отсутствии ошибки. И, соответственно, ErrorContent
— содержимое, которое будет показано при возникновении ошибки. Теперь в работающем приложении наша ошибка будет выглядеть следующим образом:
Сброс счётчика ошибок
По умолчанию, компонент ErrorBoundary
может обработать не более 100 исключений, после чего будет показано стандартное сообщение о фатальной ошибке. Если вы устанавливаете слишком широкие границы ошибок (как в первом примере — вокруг всего @body
), то это может повлечь за собой неприятные последствия, когда приложение могло бы ещё работать, но из за переполнения счётчика выбрасывается стандартное исключение. В этом случае, мы можем сбросить счётчик ошибок следующим образом:
@inherits LayoutComponentBase <PageTitle>BlazorBootstrap</PageTitle> <div class="page"> <div class="sidebar"> <NavMenu /> </div> <main> <article class="content px-4"> <ErrorBoundary @ref="errorBoundary"> <ChildContent> @Body </ChildContent> <ErrorContent> <div class="alert alert-danger" role="alert"> Произошла ошибка </div> </ErrorContent> </ErrorBoundary> </article> </main> </div> @code { private ErrorBoundary? errorBoundary; protected override void OnParametersSet() { errorBoundary?.Recover(); } }
Каждый раз, при получении параметров компонента будет выполняться метод Recover()
, который выполняет сброс счётчика ошибок и сообщает компоненту о том, что необходимо обновиться (выполняет вызов StateHasChanged
).
Итого
Компонент ErrorBoundary
позволяет локализовать место возникновения ошибки и настраивать стиль отображение сообщений об ошибках. В отличие от сообщения о фатальной ошибке, которое показывается в Blazor по умолчанию, ErrorBoundary
не блокирует пользовательский интерфейс.