Blazor - Criando uma SPA Blazor com VS Code


Hoje vamos criar uma aplicação SPA a partir de uma projeto ASP .NET Core vazio usando os recursos do Blazor.

Se você esta chegando agora e não sabe o que é o Blazor leia o artigo ASP .NET Core - Iniciando com o Blazor - Macoratti; se você já conhece e quer saber mais pode fazer o meu curso de Blazor Essencial.  

Como a versão WebAssembly ja esta esta liberada para produção é bom você atualizar os templates emitindo o comando abaixo em uma janela de comandos:

dotnet new --install Microsoft.AspNetCore.Components.WebAssembly.Templates::3.2.1

Você pode encontrar documentos e exemplos adicionais em https://blazor.net.

Criando uma aplicação SPA Blazor Server

Vamos iniciar criando uma aplicação SPA a partir de um projeto ASP .NET Core usando o template Empty.

Abra um terminal de linha de comandos,  e digite o comando :  dotnet new web -o contador

Isso vai criar um projeto ASP .NET Core  Web vazio na dentro da pasta contador:

Para abrir no VS Code basta entrar na pasta contador e digitar: code .

Vamos criar uma aplicação SPA e para isso teremos que configurar o projeto usando os recursos do Blazor. Para começar vamos definir o tipo de projeto como Blazor Server.

No Blazor Server, a construção da interface do usuário no lado do servidor é feita com base no Razor Pages, uma abordagem alternativa fornecida pela Microsoft para o padrão MVC. Ela é baseado no conceito de páginas em vez de controladores e views.

Assim vamos começar definindo no método ConfigureServices do arquivo Startup.cs, a carga da configuração do Razor Pages e Blazor Server.

Teremos também que dar suporte aos arquivos estáticos, aos endpoints e ao fallback para a página no método Configure().

Para isso vamos ter que alterar o código existente nos métodos ConfigureServices() e Configure() conforme abaixo:

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
namespace contador
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddRazorPages();
            services.AddServerSideBlazor();
        }
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            app.UseStaticFiles();
            app.UseRouting();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapBlazorHub();
                endpoints.MapFallbackToPage("/_Host");
            });
        }
    }
}

A palavra Hub no endpoints.MapBlazorHub() deve ser familiar se você já sabe como o SignalR funciona.

O código endpoints.MapFallbackToPage("/_Host") configuram a página para navegar se o recurso especificado não for encontrado e também definir a página padrão para nosso aplicativo.

Precisamos criar um arquivo chamado _Host. cshtml em uma pasta chamada Pages. A pasta Pages é obrigatória por padrão, porque o mecanismo Razor Pages procura por páginas nesse local.

Vamos então criar uma pasta Pages na raiz do projeto e nesta pasta criar o arquivo _Host.cshtml que vai conter o HTML base da aplicação e o código para renderização do componente Blazor:

@page "/"
@namespace contador.Pages
<!DOCTYPE html>
<html lang="en">
<head>
    <title>Contador</title>
</head>
<body>
@(await Html.RenderComponentAsync<Contador>(RenderMode.ServerPrerendered))
<script src="_framework/blazor.server.js"></script>
</body>
</html>

 

O Blazor usa o mesmo conceito de componente que todas os frameworks UI modernos , nas quais um conjunto de peças, chamado componentes Blazor, compõe a interface do usuário como em um quebra-cabeça. Um componente Blazor é, portanto, um parte reutilizável da interface do usuário que pode conter HTML e código C# e outros componentes do Blazor.

O método RenderComponentAsync() renderiza o componente indicado em seu parâmetro genérico (Contador) com um servidor na modalidade pré-renderizado. Esse método de renderização de um componente é uma peculiaridade do Blazor Server e não é usado, por exemplo, no Blazor WebAssembly.

O script _framework/blazor.server.js carrega o código JavaScript do Blazor que permite a comunicação com o servidor. Observe que para permitir o carregamento do script, precisamos habilitar o método app.UseStaticFiles()
na classe Startup.

Vamos criar agora o componente Blazor Contador.razor na pasta raiz.

Nosso objetivo é criar um componente que implementa uma contagem regressiva simples de 10 a 0 quando o usuário clica em um Botão.

Vamos começar definindo a interface do usuário e inicializando a contagem regressiva quando alguém clicar no botão Iniciar:

@using Microsoft.AspNetCore.Components.Web
<h1>Contador Blazor</h1>
<p>@contar</p>

<button @onclick="IniciaContagem">Iniciar</button>
@code {
    private int contar = 0;

    private void IniciaContagem()
    {
        contar = 10;
    }
}

Vamos entender o código acima:

- A diretiva @page indica o caminho no qual esse componente responde;

- A instrução using carrega os elementos do Blazor;

- A marcação define sua interface: um título, um parágrafo e um botão. É um HTML simples com algumas instruções do Razor.

- A instrução @contar grava o valor da variável contar. O framework atualiza o valor no parágrafo para você quando ela mudar.

- Quando o usuário clicar no botão Iniciar, o método IniciaContagem() será chamado graças à declaração:
@onclick = "IniciaContagem" declaração.

- O bloco @code permite definir o código C# do componente. Um arquivo Razor é uma classe C# , para que você possa criar atributos e métodos para gerenciar o status do seu componente.

- O código define o valor 10 para contar quando  o método IniciaContagem() for invocado.

Para implementar uma contagem regressiva, precisamos adicionar um timer que diminui a contagem para 0. Vamos alterar o bloco @code incluindo o código a seguir:

@using Microsoft.AspNetCore.Components.Web
@using System.Timers;
<h1>Contador Blazor</h1>
<p>@contar</p>

<button @onclick="IniciaContagem">Iniciar</button>
@code {
    private int contar = 0;

    private void IniciaContagem()
    {
         contar = 10;

         Timer timer = new Timer (1000);

         timer.Elapsed += (source, e) => 
         {
              contar--;
              InvokeAsync(() => StateHasChanged());
              if (contar == 0) timer.Stop ();
         };
         timer.Start ();
    }
}

Criamos um objeto Timer simples que executa o retorno de chamada inscrito ao evento Elapsed a cada segundo (você precisa adicionar a instrução @using System.Timers na parte superior da página para usar a classe Timer).

É simples, mas não funciona porque o código no retorno de chamada é executado em um thread separada e, quando a variável contar diminuir, a alteração não será detectada pelo framework Blazor.

Para resolver esse problema temos que alertar manualmente o framework que o estado do componente foi modificado, chamando o método StateHasChanged(), e, como esse método tem que ser chamado a partir da mesma thread da interface do usuário usamos o método InvokeAsync().

Executando o projeto iremos obter o seguinte resultado:



Temos assim uma aplicação SPA usando o Blazor Server a partir de um projeto ASP .NET Core.

Quando rodamos o projeto o HTML é renderizado no lado do servidor e o script blazor.server.js é baixado e executado no navegador.

O script começa  a conexão com a API SignalR Hubs e abre um WebSocket a partir do servidor para o cliente. O SignalR é uma biblioteca da Microsoft que permite que os dados sejam enviados do servidor para o cliente usando o canal de melhor desempenho disponível.

Quando o carregamento da página é concluído, a biblioteca cliente inicia a negociação com o servidor para escolher o melhor tipo de comunicação. Se disponível, a primeira opção é o uso do WebSocket, um protocolo padrão (RFC 6455,
padronizado para navegadores da Web pelo W3C)
que fornece um modo full-duplex canal de comunicação através de uma única comunicação TCP.

Após uma primeira resposta HTTP do tipo text/event-stream, o servidor pode enviar dados que o cliente pode receber com um simples retorno de chamada no Objeto EventSource. 

O Blazor Server usa o SignalR para enviar a atualização da interface do usuário para o cliente. Quando o usuário clica no botão, uma mensagem é enviada ao servidor que executa a solicitação e envia ao navegador as alterações a serem aplicadas ao DOM do navegador. As próximas mensagens são causadas pelo timer que a cada segundo  atualiza o contador. O contador regressivo é uma thread do servidor que atualiza a variável contar e quando o mecanismo Blazor detecta um mudança e atualiza a interface do cliente através do SignalR.

No próximo artigo veremos como criar uma aplicação SPA a partir de uma aplicação ASP .NET Core usando o Blazor WebAssembly.

Pegue o projeto aqui : contador_blazor.zip

"Se o mundo vos odeia, sabei que, primeiro do que a vós, me odiou a mim.
Se vós fôsseis do mundo, o mundo amaria o que era seu, mas porque não sois do mundo, antes eu vos escolhi do mundo, por isso é que o mundo vos odeia."

João 15:18,19

Referências:


José Carlos Macoratti