Pular para o conteúdo principal

Criando Projetos Blazor Server com Multiplos WebAssemblies

Para estruturar o consumo da API do Blazor Server pelos projetos Blazor WebAssembly (WASM) de forma limpa e escalável, a melhor estratégia é centralizar a lógica de dados. Como você gerencia múltiplos sites de clientes, duplicar o código de requisições HTTP em cada projeto geraria um pesadelo de manutenção.

Aqui está o passo a passo para arquitetar essa solução:

1. Criar uma Biblioteca de Classes Compartilhada (Shared Library)

Crie um projeto do tipo Razor Class Library (RCL) ou uma Class Library .NET Core padrão na mesma solução.
  • Modelos Únicos: Coloque nesta biblioteca todas as classes DTO (Data Transfer Objects) que a API envia e que o Blazor WASM recebe.
  • Interfaces de Serviços: Defina as regras de negócio em interfaces (ex: IClientService, IProductService).

2. Implementar os Serviços Client-Side na Biblioteca

Dentro da mesma biblioteca compartilhada, crie a implementação dessas interfaces usando o HttpClient.
public class ClientService : IClientService
{
    private readonly HttpClient _http;

    public ClientService(HttpClient http)
    {
        _http = http;
    }

    public async Task<List<ClientDto>> GetClientsAsync()
    {
        // O HttpClient já estará configurado com a URL base correta
        return await _http.GetFromJsonAsync<List<ClientDto>>("api/clients");
    }
}

3. Configurar a Injeção de Dependência no Blazor WASM

Em cada um dos projetos Blazor WebAssembly dos seus clientes, adicione a referência para a biblioteca compartilhada. No arquivo Program.cs de cada site WASM, configure o HttpClient apontando para a URL da sua API do Blazor Server:
// Program.cs do Blazor WASM
builder.Services.AddScoped(sp => new HttpClient 
{ 
    BaseAddress = new Uri("https://seusiteprincipal.com") 
});

// Registra o serviço da biblioteca compartilhada
builder.Services.AddScoped<IClientService, ClientService>();

4. Habilitar o CORS no Blazor Server

Como os sites dos clientes (WASM) rodarão em domínios ou portas diferentes da sua API principal, o navegador bloqueará as requisições por padrão. No Program.cs do seu Blazor Server (API), configure a política de CORS:
// Program.cs do Blazor Server
builder.Services.AddCors(options =>
{
    options.AddPolicy("WasmClients", policy =>
    {
        // Em produção, liste as URLs exatas dos clientes para maior segurança
        policy.AllowAnyOrigin() 
              .AllowAnyHeader()
              .AllowAnyMethod();
    });
});

app.UseCors("WasmClients");

5. Autenticação e Segurança (JWT)

Para garantir que um cliente não acesse os dados de outro:
  • Implemente autenticação baseada em Tokens JWT na API do Blazor Server.
  • No Blazor WASM, use um DelegatingHandler customizado para anexar automaticamente o token JWT no cabeçalho de cada requisição HTTP. [1]


Para organizar seu código de forma limpa e evitar duplicação, você deve criar um novo projeto do tipo Class Library (.NET Standard ou .NET 8/9) dentro da sua solução. Vamos chamá-lo de SeuProjeto.Shared.
Aqui está a estrutura exata de onde cada arquivo deve ficar:

1. No Projeto Compartilhado (SeuProjeto.Shared)

Este projeto será referenciado tanto pela API (Blazor Server) quanto por todos os sites dos clientes (Blazor WASM).
  • 📂 Pasta: DTOs
    • O que fica aqui: As classes de transferência de dados (ex: ClienteDto.cs, PedidoDto.cs, LoginRequest.cs).
    • Motivo: A API precisa saber o formato dos dados que vai enviar, e o WASM precisa saber o formato dos dados que vai receber.
  • 📂 Pasta: Interfaces
    • O que fica aqui: As interfaces dos contratos de serviço (ex: IClienteService.cs, IProdutoService.cs).
    • Motivo: Permite que o Blazor WASM use a interface para fazer requisições HTTP, enquanto o Blazor Server pode usar a mesma interface para buscar dados diretamente do banco de dados (se você desejar).
  • 📂 Pasta: Services (Opcional, apenas os clients HTTP)
    • O que fica aqui: A implementação da lógica que faz o HttpClient.GetFromJsonAsync (ex: ClienteHttpClientService.cs).
    • Motivo: Centraliza a escrita de código de requisição web. Nenhum projeto WASM precisará reescrever códigos de fetch do HTTP.

2. No Projeto Principal (SeuProjeto.Server / API)

Este projeto terá a referência de SeuProjeto.Shared.
  • 📂 Pasta: Controllers (ou Endpoints)
    • O que fica aqui: Seus controladores API (ex: ClientesController.cs). Eles recebem as requisições HTTP do WASM, chamam a lógica do banco de dados e retornam os DTOs que estão na pasta compartilhada.
  • 📂 Pasta: Services (Implementação de Banco)
    • O que fica aqui: A lógica real que consulta o banco de dados via Entity Framework (ex: ClienteSqlService.cs).

3. Nos Projetos dos Clientes (SeuProjeto.ClientWasm1, SeuProjeto.ClientWasm2, etc.)

Estes projetos apenas consomem a estrutura pronta. Eles terão a referência de SeuProjeto.Shared.
  • Não criam pastas de DTOs ou Interfaces.
  • Arquivo Program.cs: Você apenas registra a interface e o serviço que vieram do projeto compartilhado.
  • Nas páginas Razor: Você apenas injeta a interface.
    @inject IClienteService ClienteService
    

Para te ajudar a dar o próximo passo na configuração, você prefere ver um exemplo prático de como criar o código da interface e do serviço HTTP que conecta os dois lados, ou quer focar primeiro em como configurar o arquivo Program.cs do WASM para injetar essas dependências?

Comentários

Postagens mais visitadas deste blog

UML e comunicação entre Componentes

(conteúdo gerado com I.A.) Antes de abordarmos o conceito de Componentes, vale a pena analisar como um programador iniciante costuma estruturar uma aplicação. Geralmente, a escolha é construir um monólito tradicional, agrupando todas as classes de domínio (como Categoria, Produto, Compra, Venda, Pagamento, etc.) em uma única pasta de Entidades. Da mesma forma, criam-se pacotes globais para Repositórios, Serviços e Controllers. O grande problema dessa abordagem é que ela gera um forte acoplamento entre as classes e as camadas do sistema. À medida que a aplicação cresce, isso desencadeia uma série de dificuldades: Manutenção e modelagem complexas: As responsabilidades se misturam. Rapidamente, o código passa a ter diversos trechos onde as classes assumem funções que não deveriam ter, tornando a evolução do sistema confusa. Escalabilidade ineficiente: Para escalar o backend, é necessário replicar a aplicação inteira e todo o banco de dados. Além de consumir mais recursos, isso traz o ri...

Quando escolher Flask ou Quart no Python

Atualmente , considerando o suporte assíncrono já presente no Flask, a escolha entre Flask e Quart para uma API Server depende de vários fatores técnicos. Vejamos alguns critérios: Fonte:  https://pt.stackoverflow.com/questions/51268/qual-a-diferen%C3%A7a-entre-comunica%C3%A7%C3%A3o-ass%C3%ADncrona-e-s%C3%ADncrona Suporte Assíncrono : Flask : O Flask oferece suporte assíncrono por meio de extensões de terceiros, como  flask[async] . No entanto, seu desempenho assíncrono é inferior aos frameworks nativamente assíncronos. Quart : O Quart é uma reimplantação do Flask baseada no padrão ASGI (Asynchronous Server Gateway Interface). Ele utiliza E/S assíncrona em todo o código e é mais adequado para bases de código predominantemente assíncronas. Desempenho : Flask : Como aplicação WSGI, o Flask usa um único worker para cada ciclo de solicitação/resposta. Quando uma solicitação chega a uma visualização assíncrona, o Flask inicia um loop de eventos em uma thread, executa a função da vi...

Metodo para criar relacionamento entre tabelas sem dar erro cíclico EFCore

Quando estamos modelando o banco de dados no Entity Framework Core (ou em qualquer outra ferramenta) é muito comum criarmos o erro cíclico. Este erro ocorre devido ao banco de dados não conseguir determinar onde o relacionamento termina, causando um erro de loop. Vejamos uma situação real onde foi gerado esse problema: Um Professor leciona em várias Turmas, Um Professor leciona uma ou mais Disciplinas, Um Professor leciona determinadas Disciplinas em determinadas Turmas, Uma Turma tem muitos Professores, Em todas as Turmas tem 9 Disciplinas. Em todas as turmas podem ter até 9 Professores. Só por essa descrição já é possível perceber que os relacionamentos podem ser complexos de entender. E tem-se também o problema da navegação em via dupla: Professor-Turmas, Turma-Professores. Então, como modelar essas tabelas sem que o banco entre em loop? Para resolver esse problema no Entity Framework Core e evitar o erro de "Multiple Cascade Paths" (caminhos múltiplos de cascata) comum n...