.NET 6  - Blazor :  Criando um componente de dados


 Hoje veremos como criar um componente de dados no Blazor no ambiente do .NET 6.

Os componentes são o coração do Blazor e uma aplicação Blazor consiste em um ou mais Componentes Razor. Normalmente, um componente hospeda sua UI usando a marcação HTML e a lógica associada.

No entanto, às vezes você deseja que o componente pai especifique fragmentos da IU para que esses fragmentos possam ser renderizados para produzir a IU final do seu componente.

Esses fragmentos de IU são chamados de templates ou modelos. Se você já trabalhou com os controles vinculados a dados do ASP.NET Web Form, como GridView, ListView e DataList, você já está familiarizado com a ideia de modelos e controles modelados.

No Blazor você também pode criar facilmente componentes com modelo de dados para que seu componente se torne mais reutilizável e personalizável.

Neste artigo vamos criar um Componente Blazor chamado DataList que será usado para exibir uma lista de funcionários e uma lista de clientes que iremos obter a partir do banco de dados Northwind.mdf usando as tabelas Customers e Employees.

Vamos usar o EF Core 6 no ambiente do .NET 6 para realizar o acesso ao banco de dados.

Nota: Você pode obter o banco de dados Northwind.mdf a partir deste link.

Para consumir o componente DataList vamos criar dois componentes:

  1. DataListCustomer  - Exibe os dados dos Customers
  2. DataListEmployee  - Exibe os dados dos Employees

Para mais detalhes sobre como criar componentes modelados veja a documentação aqui.

recursos usados:

Criando o projeto no VS 2022

Vamos criar um novo projeto Blazor Server usando o template Blazor Server App:

Informe o nome Blazor_Component ao projeto e solução e defina as configurações conforme abaixo:

Nota: Estamos usando o .NET 6.0 RC 2.

Vamos limpar o projeto removendo os arquivos FetchData.razor, Counter.razor da pasta Pages e  vamos remover o conteúdo da pasta Data do projeto. A seguir remova também as referências não usadas no arquivo Program.

Configurando o projeto

A seguir inclua no projeto uma referência ao pacote : Microsoft.EntityFrameworkCore.SqlServer 6.0.0-rc.2.214805

A seguir vamos criar na pasta Data as classes Customer e Employee que representam os dados que iremos acessar e também vamos criar o arquivo de contexto do EF Core chamado AppDbContext.

1- Customer

using System.ComponentModel.DataAnnotations.Schema;


    [Table("Customers")]
    public class Customer

    {
        public string? CustomerID { get; set; }
        public string? CompanyName { get; set; }
        public string? ContactName { get; set; }
        public string? Country { get; set; }
    }

2- Employee

using System.ComponentModel.DataAnnotations.Schema;

    [Table("Employees")]
    public class Employee

    {
        public int EmployeeID { get; set; }
        public string? FirstName { get; set; }
        public string? LastName { get; set; }
        public string? Title { get; set; }
    }

3- AppDbContext

using Microsoft.EntityFrameworkCore;

public class AppDbContext : DbContext
{
    public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
    {
    }

    public DbSet<Employee>? Employees { get; set; }
    public DbSet<Customer>? Customers { get; set; }

}

Depois inclua no arquivo appsettings.json a string de conexão com o banco de dados Northwind.mdf:

{
  "ConnectionStrings": {
    "DefaultConnection": "Data Source=.\SQLEXPRESS;Initial Catalog=Northwind;Integrated Security=True"
  },

  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*"
}

Após isso vamos configurar o arquivo Program registrando o serviço do contexto, o provedor do banco de dados e obtendo a string de conexão.

Abra a classe Program e inclua o código a seguir:

using Microsoft.EntityFrameworkCore;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();

var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");

builder.Services.AddDbContext<AppDbContext>(options => options.UseSqlServer(connectionString));

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();

app.MapBlazorHub();
app.MapFallbackToPage("/_Host");

app.Run();

Criando o componente DataList

Na pasta Pages crie o componente DataList usando  a diretiva @typeparam que especifica o nome do parâmetro de tipo genérico. Este nome é usado posteriormente ao definir os modelos (é como o parâmetro T nos genéricos C #).

@typeparam DataItemType

<table border="1" cellpadding="10"> 
    <thead> 
        <tr>@HeaderTemplate</tr> 
    </thead> 
    <tbody> 
       @foreach (var item in DataItems)
       {
           <tr>@ItemTemplate(item)</tr>
       }
    </tbody> 
    <tfoot> 
        <tr>@FooterTemplate</tr> 
    </tfoot> 
</table> 

@code
    [Parameter] 
    public List<DataItemType>? DataItems { get; set; } 

    [Parameter] 
    public RenderFragment? HeaderTemplate { get; set; } 
     

    [Parameter] 
    public RenderFragment<DataItemType>? ItemTemplate { get; set; }
     

    [Parameter] 
    public RenderFragment
? FooterTemplate { get; set; } 
}

Neste código definimos quatro propriedades de parâmetro :

  1. DataItems
  2. HeaderTemplate
  3. ItemTemplate
  4. FooterTemplate

A propriedade DataItems contém uma lista de itens de dados que são processados pelo controle. Em nosso exemplo, especificamos que seja um List<DataItemType>, mas pode ser qualquer outro objeto de acordo com sua necessidade.

A propriedade HeaderTemplate é um RenderFragment que representa a interface do usuário exibida no cabeçalho do DataList. O FooterTemplate é bastante semelhante ao HeaderTemplate. O ItemTemplate é um RenderFragment<DataItemType>.

Dessa forma, o ItemTemplate pode iterar pelos itens de dados e renderizar cada item na IU.

Na seção HTML do código definimos uma tabela com as seções :  thead, tbody e tfoot.

O HeaderTemplate e FooterTemplate são renderizados nas seções thead e tfoot, respectivamente. Os itens de dados são renderizados iterando por meio de DataItems e renderizando o ItemTemplate para cada item de dados.

Criando o componente DataListCustomer

Vamos criar agora um outro componente chamado DataListCustomer que vai usar o componente DataList para exibir os dados da tabela Customer.

Crie o componente DataListCustomer na pasta Pages com o seguinte código:

@page "/datalistcustomers" 
@inject AppDbContext db

@code {

    [Parameter]
    public List<Customer>? CustomerData { get; set; }  

    protected override void OnInitialized()
    {
        CustomerData = db.Customers.Take(10).ToList();
    } 
}
@if (CustomerData != null) 

     <h3>Lista de Clientes</h3>
    <DataList DataItems="@CustomerData"> 
        <HeaderTemplate
            <th>Customer ID</th> 
            <th>Company Name</th> 
            <th>Contact Name</th>
            <th>Country</th>
        </HeaderTemplate> 
        <ItemTemplate
            <td>@context.CustomerID</td> 
            <td>@context.CompanyName</td> 
            <td>@context.ContactName</td> 
            <td>@context.Country</td> 
        </ItemTemplate> 
        <FooterTemplate
            <td colspan="3">
                <h3>Total de Clientes :
                    @CustomerData.Count</h3>
            </td> 
        </FooterTemplate> 
    </DataList> 
}

Neste código configuramos a rota do componente (/datalistcustomers) para que ele possa ser acessado como uma "page". Em seguida, injetamos uma instância de AppDbContext porque precisamos recuperar os dados posteriormente no componente.

No método OnInitialized() estamos acessando o banco de dados usando a instância do contexto e obtendo uma lista de clientes.

A seguir verificamos se existem dados a exibir e estamos usando o componente DataList para montar o leiaute da exibição dos dados.

Criando o componente DataListEmployee

Vamos criar agora um outro componente chamado DataListEmployee que vai usar o componente DataList para exibir os dados da tabela Employee.

Crie o componente DataListEmployee na pasta Pages com o seguinte código:

@page "/datalistemployee" 
@inject AppDbContext db

@code {

    [Parameter]
    public List<Employee>? EmployeeData { get; set; }  

    protected override void OnInitialized()
    {
        EmployeeData = db.Employees.Take(5).ToList();
    } 
}

@if (EmployeeData != null) 

    <DataList DataItems="@EmployeeData" Context="context" DataItemType="Employee"> 
        <HeaderTemplate> 
            <td  align="center">
                <h3>Lista de Funcionários</h3>
            </td>
        </HeaderTemplate> 
        <ItemTemplate> 
             <table cellpadding="5">
                <tr>
                    <td align="right">Employee ID :</td>
                    <td align="left">@context.EmployeeID</td>
                </tr>
                 <tr>
                    <td align="right">First Name :</td>
                    <td align="left">@context.FirstName</td>
                </tr>
                 <tr>
                    <td align="right">Last Name :</td>
                    <td align="left">@context.LastName</td>
                </tr>
                 <tr>
                    <td align="right">Title :</td>
                    <td align="left">@context.Title</td>
                </tr>
            </table>
        </ItemTemplate> 
        <FooterTemplate> 
            <td  align="center">
                <h3>Total de Funcionários : @EmployeeData.Count</h3>
            </td> 
        </FooterTemplate> 
    </DataList> 
}

A lógica usada neste componente é exatamente a mesma a diferença é que definimos um leiaute diferente para exibir os dados dos funcionários.

Em ambos os componente note que na marcação <DataList> definimos 3 propriedades : DataItemType, DataItems e Context.

O DataItemType especifica o tipo dos itens de dados. Nesse caso, queremos exibir uma lista de funcionários e/ou clientes e, portanto, DataItemType pode ser Employee ou Customer.

A propriedade DataItems contém os dados reais.

Podemos também pode especificar Context no ItemTemplate. Observe que especificar DataItemType e Context é opcional. Se você não especificar DataItemType, ele será inferido a partir dos dados. Se você não especificar o Contexto, o contexto do nome do parâmetro padrão será assumido.

Dentro de <DataList>, especificamos a IU para <HeaderTemplate>, <ItemTemplate> e <FooterTemplate>.

Observe que esses nomes de elemento de marcação devem corresponder aos nomes de propriedade correspondentes (HeaderTemplate, ItemTemplate e FooterTemplate) definidos no componente DataList.

Testando o componente de dados

Agora basta ajustar o arquivo NavMenu e incluir os links para acessar Customers e Employees :

...
 <div class="nav-item px-3">
    <NavLink class="nav-link" href="datalistcustomers">
         <span class="oi oi-plus" aria-hidden="true"></span> Customers
     </NavLink>
</div>
<div class="nav-item px-3">
    <NavLink class="nav-link" href="datalistemployee">
        <span class="oi oi-plus" aria-hidden="true"></span> Employees
    </NavLink>
...
</div>

Executando o projeto iremos obter o seguinte resultado:

Pegue o projeto aqui: Blazor_Component.zip

"Ai dos que ao mal chamam bem, e ao bem mal; que fazem das trevas luz, e da luz trevas; e fazem do amargo doce, e do doce amargo!"
Isaías 5:20

Referências:


José Carlos Macoratti