Blazor WebAssembly - Comunicação entre componentes

Neste artigo veremos como realizar a comunicação entre componentes em uma aplicação Blazor WebAssembly(WASM).

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 curso de Blazor Essencial.  


Para mostrar como realizar a comunicação entre componentes vamos criar uma aplicação Blazor WASM e vamos enviar mensagens de um componente Index para o componente MainLayout usando um serviço de mensagens.
 
Uma forma de realizar a comunicação entre quaisquer dois componentes em um aplicativo blazor é usar eventos e delegates C#.
 
Assim, é importante que você conheça os conceitos relacionados a eventos e delegates. Veja nas referências os artigos sobre esses assuntos.

Uma das principais vantagens do uso de eventos é que uma classe que publica um evento não precisa saber os detalhes dos assinantes em tempo de projeto. Como os eventos são baseadas em delegados (delegates), os assinantes só são adicionados quando o programa está sendo executado.

Existem três etapas para criar um manipulador de eventos dentro de uma classe na linguagem C#:

  1. Em primeiro lugar é preciso de um delegado.O delegado é usado para armazenar os dados dos assinantes para o evento;
  2. Em segundo lugar, um evento público deve ser criado. Este evento é visível externamente à classe e é usado para criar as inscrições em eventos;
  3. Finalmente, um método deve ser criado dentro da classe. O método contém o código que aciona o evento;

Assim em nosso exemplo teremos :

  1. Uma classe publisher que é o publicador e que declara um evento com o tipo de manipulador necessário para o evento (também conhecido como delegate).
     
  2. Uma classe  subscriber que é o  assinante que se inscreve em um evento adicionando um método manipulador (que corresponde ao delegado do evento) ao evento da classe do editor (Ex: publisher.onEvent + = myEventHandler;), e cancela a assinatura removendo o manipulador de eventos (Ex: publisher.onEvent - = myEventHandler;)
Recursos usados:
Criando o projeto Razor Page
 
Vamos criar um projeto Blazor no VS 2019 Community chamado Blazor_Comunicate1;
 
 
Nota: Observe que eu já estou usando o NET 5.0.
 
Ao clicar no botão Create teremos o projeto criado com a seguinte estrutura:
 
 
Observe que não temos mais o arquivo Startup no projeto. As configurações são definidas no arquivo Program conforme vemos a seguir:
 
public class Program
{
    public static async Task Main(string[] args)
    {
        var builder = WebAssemblyHostBuilder.CreateDefault(args);
        builder.RootComponents.Add<App>("#app");
        builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
        await builder.Build().RunAsync();
     }
}
 
Criando o serviço de mensagem
 
Vamos agora criar uma pasta Services no projeto e nesta basta criar a interface IMensagemService a seguir a sua implementação na classe MensagemService:
 
1- IMensagemService
 
using System;
namespace Blazor_Comunicate1.Services
{
    public interface IMensagemService
    {
        event Action<string> OnMensagem;
        void EnviaMensagem(string message);
        void LimpaMensagens();
    }
}
 
Neste código declaramos o evento OnMensagem que requer um delegate do manipulador do tipo Action<string>, que é um método do manipulador que aceita um único parâmetro string e retorna void (Ex:, void MessageHandler (string mensagem) {}).
 
2- MensagemService
 
using System;
namespace Blazor_Comunicate1.Services
{
    public class MensagemService : IMensagemService
    {
        public event Action<string> OnMensagem;
        public void EnviaMensagem(string message)
        {
            OnMensagem?.Invoke(message);
        }
        public void LimpaMensagens()
        {
            OnMensagem?.Invoke(null);
        }
    }
}

Esta classe implementa a interface e no código temos o método EnviaMensagem que invoca o evento OnMensagem com o parâmetro de mensagem. Aqui usamos o operador condicional nulo (?.) para verificar se OnMensagem é nulo antes de tentar invocá-lo, lembrando que um evento é nulo quando não tem assinantes.
 
A seguir precisamos registrar o serviço no arquivo Program:
 
 public class Program
    {
        public static async Task Main(string[] args)
        {
            var builder = WebAssemblyHostBuilder.CreateDefault(args);
            builder.RootComponents.Add<App>("#app");

            builder.Services.AddSingleton<IMensagemService, MensagemService>();

            builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });

            await builder.Build().RunAsync();
        }
    }


E precisamos incluir o namespace do serviço no arquivo _Imports.razor :
 
@using System.Net.Http
@using System.Net.Http.Json
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.AspNetCore.Components.WebAssembly.Http
@using Microsoft.JSInterop
@using Blazor_Comunicate1
@using Blazor_Comunicate1.Shared
@using Blazor_Comunicate1.Services

Definindo o envio da mensagem

Vamos a seguir alterar o código do componente Index.razor e definir o envio da mensagem:
 

@page "/"
@inject IMensagemService MensagemService
<div class="card mb-3">
    <h4 class="card-header">Blazor WebAssembly Component Communication</h4>
    <div class="card-body">
        <button @onclick="EnviaMensagem" class="btn btn-primary mr-2">Envia Mensagem</button>
        <button @onclick="LimpaMensagens" class="btn btn-secondary">Limpa Mensagens</button>
    </div>
</div>
@code {
    private void EnviaMensagem()
    {
        MensagemService.EnviaMensagem("Mensagem enviada do componente Index para o componente MainLayout !");
    }
    private void LimpaMensagens()
    {
        MensagemService.LimpaMensagens();
    }
}

Aqui injetamos o serviço no componente e usamos os métodos para enviar e limpar mensagens.

Consumindo a mensagem

Agora vamos alterar o código do componente MainLayout que vai consumir as mensagens:

@inherits LayoutComponentBase
@implements IDisposable
@inject IMensagemService MensagemService
<div class="container text-center my-3">
    @Body
    @foreach (var mensagem in mensagens)
    {
        <div class="alert alert-sm alert-info">@mensagem</div>
    }
</div>
@code {
    private List<string> mensagens = new List<string>();
    protected override void OnInitialized()
    {
        // se inscreve no evento OnMensagem
        MensagemService.OnMensagem += MessageHandler;
    }
    public void Dispose()
    {
        // cancela inscrição no evento OnMensagem
        MensagemService.OnMensagem -= MessageHandler;
    }
    private void MessageHandler(string mensagem)
    {
        if (mensagem != null)
            mensagens.Add(mensagem);
        else
            mensagens.Clear();
        StateHasChanged();
    }
}

Aqui o componente de MainLayout usa o serviço de mensagem para assinar novas mensagens e adicioná-las à lista de mensagens que é renderizada abaixo de @Body em um laço @foreach,

Um mensagem nula informa ao componente para limpar a lista de mensagens. Depois que uma mensagem é recebida, o método StateHasChanged () é chamado para acionar uma atualização na IU.

Agora é só alegria...

Executando o projeto veremos a comunicação entre os componentes conforme abaixo:

Pegue o projeto aqui:   Blazor_Comunicate1.zip (sem as referências)

 

Referências:


José Carlos Macoratti