Blazor - Usando os conceitos da Clean Architecture - II

Hoje vamos criar uma aplicação Blazor usando os conceitos da Clean Architecture.

Continuando a primeira parte do artigo vamos implementar a camada de apresentação representada pelo projeto Blazor.

O projeto Blazor

Nosso projeto Blazor vai ser composto pelos componentes : ProcuraProduto.razor que vai usar os componentes ProcuraProdutoComponent e ProdutoItemComponent e também o componente ExibeProduto:

  1. ProcuraProduto - Exibe o catálogo de produtos
     
    • ProcuraProdutoComponent  - responsável por exibir a barra para procurar um produto;
    • ProdutoItemComponent - responsável por exibir os dados de um produto;
       
  2. ExibeProduto - Exibe os detalhes de um produto selecionado;

Na figura abaixo temos o componente ProcuraProduto usando os componentes ProcuraProdutoComponent e ProdutoItemComponent:

A primeira coisa a fazer no projeto Blazor e realizar a injeção dos serviços que definimos nos demais projetos. Fazemos isso no método ConfigureServices da classe Startup:

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace eCatalogo.Blazor
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }
        public IConfiguration Configuration { get; }
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddRazorPages();
            services.AddServerSideBlazor();
            services.AddTransient<IProdutoRepository, ProdutoRepository>();
            services.AddTransient<IProcuraProduto, ProcuraProduto>();
            services.AddTransient<IExibeProduto, ExibeProduto>();
        }
  ...
}

 

Vamos aproveitar e definir no arquivo NavMenu.razor as opções do menu que iremos usar para acessar o catálogo de produtos:

<div class="@NavMenuCssClass" @onclick="ToggleNavMenu">
    <ul class="nav flex-column">
        <li class="nav-item px-3">
            <NavLink class="nav-link" href="" Match="NavLinkMatch.All">
                <span class="oi oi-home" aria-hidden="true"></span> Home
            </NavLink>
        </li>
        <li class="nav-item px-3">
            <NavLink class="nav-link" href="produtos">
                <span class="oi oi-plus" aria-hidden="true"></span> Catálogo de Produtos
            </NavLink>
        </li>
    </ul>
</div>

Na pasta wwwroot vamos criar a pasta images e incluir a imagem produtos.jpg que iremos usar no componente Index.razor.

Criando os componentes na pasta Shared

A seguir vamos iniciar a criação dos componentes ProcuraProdutoComponent e ProdutoItemComponent que iremos usar para montar o catálogo de produtos. Vamos criar esses componentes na pasta Shared do projeto.

1- ProdutoItemComponent.razor

@if (this.Produto != null)
{
    <tr>
        <td>
            <NavLink href="@($"produto/{Produto.ProdutoId}")">
                @Produto.Nome
            </NavLink>
        </td>
        <td>@Produto.Categoria</td>
        <td>@Produto.Preco.ToString("c")</td>
    </tr>
}
@code {
    [Parameter]
    public Produto Produto { get; set; }
}

Este componente vai receber um produto como parâmetro e vai exibir os dados deste produto.

1- ProcuraProdutoComponent.razor

<form class="form-inline">
    <div class="form-group mx-sm-3 mb-2">
        <label for="filter">Procurar:&nbsp;</label>
        <input type="text" class="form-control" id="filter" @bind-value="filter" />
    </div>
    <button type="button" class="btn btn-primary mb-2" @onclick="HandleSearch">Procurar</button>
</form>
@code {
    private string filter;
    [Parameter]
    public EventCallback<string> OnSearch { get; set; }
    private void HandleSearch()
    {
        OnSearch.InvokeAsync(filter);
    }
}

Este componente permite filtrar os produtos exibidos no catálogo de produtos.

Criando os componentes na pasta Pages

Vamos agora criar os componentes ProcuraProduto e ExibeProduto, iniciando com o componente ProcuraProduto que exibe o catálogo de produtos e usa os dois componentes definidos acima para montar o catálogo e filtrar os produtos usando um critério.

a- ProcuraProduto.razor

@page "/produtos"
@inject IProcuraProduto procuraProduto
<h3>Procura Produtos</h3>
<br />
<ProcuraProdutoComponent OnSearch="HandleSearch"></ProcuraProdutoComponent>
<br />
<table class="table">
    <thead>
        <tr>
            <th>Nome</th>
            <th>Categoria</th>
            <th>Preço</th>
        </tr>
    </thead>
    <tbody>
        @if (produtos != null && produtos.Count() > 0)
        {
            @foreach (var produto in produtos)
            {
                <ProdutoItemComponent Produto="produto"></ProdutoItemComponent>
            }
        }
        else
        {
            <tr>
                <td colspan="3">
                    Não foi possível encontrar produtos
                </td>
            </tr>
        }
    </tbody>
</table>
@code {
        private IEnumerable<Produto> produtos;
    protected override void OnInitialized()
    {
        produtos = procuraProduto.Execute();
    }
    private void HandleSearch(string filter)
    {
        produtos = procuraProduto.Execute(filter);
    }
}

A seguir vamos definir o componente ExibeProduto que vai receber o id de um produto e vai montar um Card usando os recursos do Bootstrap e exibir os detalhes do produto:

b- ExibeProduto.razor

@page "/produto/{id:int}"
@inject IExibeProduto exibeProduto
<h3>Produto - Detalhes</h3>
<div class="card" style="width: 38rem;">
    <div class="card-body">
        <img src="@produto.ImagemUrl" />
        <h5 class="card-title">@produto.Nome</h5>
        <h6 class="card-subtitle mb-2 text-muted">@produto.Categoria</h6>
        <hr />
        <p>
            Preço: <label style="color:darkred">@produto.Preco.ToString("c")</label>
        </p>
        <p class="card-text">@produto.Descricao</p>
    </div>
</div>
<br />
<NavLink href="produtos">Retornar</NavLink>
@code {
    private Produto produto;
    [Parameter]
    public int Id { get; set; }
    protected override void OnParametersSet()
    {
        if (Id > 0)
            produto = exibeProduto.Execute(Id);
    }
}

 

Agora é só alegria...

Executando o projeto teremos o resultado abaixo:

Pegue o projeto aqui :   eCatalogo.zip

"Rogo-vos, pois, irmãos, pela compaixão de Deus, que apresenteis os vossos corpos em sacrifício vivo, santo e agradável a Deus, que é o vosso culto racional."
Romanos 12:1


Referências:


José Carlos Macoratti