Blazor - Apresentando Error Boundaries (NET 6) - I


Neste artigo vou apresentar o novo componente  Error Boundaries do Blazor para realizar o tratamento de erros.

O Blazor é um framework SPA onde o navegador atua como host do aplicativo e é o canal de processamento para componentes do Razor com base em solicitações de URI para navegação e ativos estáticos.

Ao contrário dos aplicativos ASP.NET Core que são executados no servidor com um pipeline de processamento de middleware, não há pipeline de middleware que processa solicitações de componentes do Razor que podem ser aproveitados para tratamento de erros global. No entanto, um aplicativo pode usar um componente de processamento de erros como um valor em cascata para processar erros de maneira centralizada.

O novo componente ErrorBoundary ou Limite de Erro pode ser entendido como um componente que pode conter os erros da aplicação. Assim se a sua aplicação contém um erro que não foi tratado por um bloco try/catch, ao invés da aplicação parar de funcionar, este componente pode ser usado para exibir uma interface de usuário personalizada.

Neste contexto o novo componente ErrorBoundary foi introduzido para tratar o erro não tratado a nível de UI fornecendo uma abordagem conveniente para lidar com exceções. Usando este componente podemos lidar com os erros em uma seção ou área específica da página para que a página restante do aplicativo seja executada sem problemas.

O componente ErrorBoundary:

1- Processa seu conteúdo filho <ChildContent> quando um erro não ocorre;
2- Processa a IU de erro <ErrorContent> quando uma exceção não tratada for lançada;

Este componente atua como um invólucro ou wrapper e como ele podemos:

  1. Envolver o elemento '@Body' em 'shared/MainLaout.razor', então isso significa que seu escopo é global (significa tratamento de erro no nível da página), então qualquer erro que ocorrer dentro de qualquer componente da página e, em seguida, a página inteira irá mostrar uma mensagem de erro.
     
  2. Envolver qualquer componente do Blazor, então ele exibirá o conteúdo se não houver erro, mas se qualquer componente filho gerar um erro, ele mostrará a mensagem de erro.
     

De forma geral, para definir um limite de erro, use o componente ErrorBoundary para envolver o conteúdo existente.

ErrorBoundary com escopo global

Vamos iniciar mostrando um exemplo para o primeiro caso.

Em um projeto Blazor Server criado no VS 2022 com o nome Blazor_ErrorBoundaries vamos envolver o elemento @Body do componente MainLayout.razor com o componente ErrorBoundary:

@inherits LayoutComponentBase

<PageTitle>Blazor_ErrorBoundaries</PageTitle>

<div class="page">
    <div class="sidebar">
        <NavMenu />
    </div>
    <main>
        <div class="top-row px-4">
            <a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
        </div>
        <article class="content px-4">
             <ErrorBoundary>
                  @Body
            </ErrorBoundary>

        </article>
    </main>
</div>

O aplicativo continua a funcionar normalmente, mas o limite de erro lida com exceções não tratadas.

Então agora vamos definir o código a seguir no componente Counter do projeto para lançar uma exceção quando o contador for maior que 3:

@page "/counter"

<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 > 3)
        {
            throw new InvalidOperationException("O contador atingiu o limite definido !");
        }

    }
}

Qual será o comportamento quando o contador for maior que 3 ?

Se a exceção não tratada for lançada para um currentCount acima de 3 teremos que :

Por padrão, o componente ErrorBoundary renderiza um elemento <div> vazio com a classe CSS blazor-error-boundary para seu conteúdo de erro. As cores, o texto e o ícone da IU padrão são definidos usando CSS na folha de estilo do aplicativo na pasta wwwroot, portanto, você está livre para personalizar a IU de erro.

Podemos alterar o conteúdo de erro padrão definindo a propriedade ErrorContent e personalizando a mensagem. Para isso precisamos renderizar 2 componentes filhos dentro de 'ErrorBoundary' como 'ChildContent', 'ErrorContent' e especificar a mensagem dentro de ErrorContent:

@inherits LayoutComponentBase

<PageTitle>Blazor_ErrorBoundaries</PageTitle>

<div class="page">
    <div class="sidebar">
        <NavMenu />
    </div>
    <main>
        <div class="top-row px-4">
            <a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
        </div>
        <article class="content px-4">
             <ErrorBoundary>
              <ChildContent>
                   @Body
               </ChildContent>
                <ErrorContent>
                      <h1 style="color: red;">Opa... Ocorreu um erro no contador</h1>
                </ErrorContent>
              </ErrorBoundary>

        </article>
    </main>
</div>

Executando o projeto novamente e acionando o contador mais de 3 vezes teremos :

Assim no exemplo visto até aqui, como aplicamos o componente 'ErrorBoundary' em torno de '@Body' isso fará com que mesmo navegando para outras páginas, ele ainda vai continuar mostrando a mensagem de erro em todas as páginas porque o nível da página esta como escopo global.

Como definimos o componente ErrorBoundary no layout   a exibição da UI do erro será vista independentemente da página para a qual o usuário navegou.  Dessa forma recomenda-se definir limites de erro de escopo restrito na maioria dos cenários. Se você definir um escopo amplo de um limite de erro, poderá redefini-lo para um estado sem erro em eventos de navegação de página subsequentes chamando o método Recover do limite de erro.

Portanto, para corrigir o problema acima, temos que chamar o método 'Recover' da instância 'ErrorBoundary' e assim o método 'Recover' irá limpar a mensagem de erro. Para isso defina o código a seguir:

@inherits LayoutComponentBase

<PageTitle>Blazor_ErrorBoundaries</PageTitle>

<div class="page">
    <div class="sidebar">
        <NavMenu />
    </div>
    <main>
        <div class="top-row px-4">
            <a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
        </div>
        <article class="content px-4">
          
<ErrorBoundary @ref="@errorBoundary">
            <ChildContent>
                @Body
            </ChildContent>
            <ErrorContent>
                <h1 style="color: red;">Opa... Ocorreu um erro no contador</h1>
            </ErrorContent>
           </ErrorBoundary>
        </article>
    </main>
</div>
@code{
    private ErrorBoundary?
errorBoundary
;

    protected override void OnParametersSet()
    {
      
 errorBoundary?.Recover();
    }
}

Neste código temos que :

- O atributo '@ref' fornece o controle sobre o componente 'ErrorBoundry' em nossa lógica C#.

- No código C# temos a declaração da variável 'ErrorBoundary' que será usada pelo componente HTML para obter controle sobre o componente 'ErrorBounary'.

- O  método 'OnParameterSet'  esta sendo invocado para cada mudança de rota, portanto, dentro dele, se chamarmos o método 'Recover', a mensagem de erro desaparecerá ao navegar para outras páginas;

Dessa forma a exibição da mensagem de erro será limpa após a chamada do método Recover().

Na próxima parte do artigo veremos como usar o componente ErrorBoundary com um escopo limitado a um componente.

Pegue o código do projeto aqui:   Blazor_ErrorBoundaries.zip (sem as referências)

"E tu, ó menino, serás chamado profeta do Altíssimo, Porque hás de ir ante a face do Senhor, a preparar os seus caminhos; Para dar ao seu povo conhecimento da salvação, Na remissão dos seus pecados;"
Lucas 1:76,77

Referências:


José Carlos Macoratti