Blazor - Navegação de formulário aprimorada - II


   Neste artigo veremos a navegação de formulário aprimorada no Blazor.

Continuando o artigo anterior veremos agora na prática o uso da navegação de formulário aprimorada no Blazor.

Para isso vamos usar outro recurso que é o Blazor Scaffolder e vamos criar em um projeto Blazor Web App uma aplicação que vai realizar o CRUD básico gerenciando informações de produtos usando o banco de dados SQLite e o EF Core.

Criando o projeto

Vamos criar um novo projeto chamado BlazorForms no VS 2022 Preview usando o template Blazor Web App.

Usando a seguinte configuração :

A seguir vamos incluir no projeto os pacotes nuget:

Microsoft.EntityFrameworkCore.Sqlite
Microsoft.EntityFrameworkCore.Design

No projeto vamos criar as pastas Entities e Context.

Na pasta Entities vamos criar a classe Product:

public class Product
{
   public int Id { get; set; }
   public string Name { get; set; } = string.Empty;
   public string Description { get; set; } = string.Empty;
}

Na pasta Context vamos criar a classe de contexto AppDbContext:

public class AppDbContext : DbContext
{
    public AppDbContext(DbContextOptions options) : base(options)
    {
    }
    public DbSet<Product> Products { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Product>().HasData(
            new Product
            {
                Id = 1,
                Name = "Apple Keyboard iPad",
                Description = "Apple Smart Keyboard for iPad",
                Price = 69.00M
            },
            new Product
            {
                Id = 2,
                Name = "Apple IPhone 15",
                Description = "Apple IPhone 15 64GB GSM",
                Price = 1299.00M
            }
        );
    }
}

No arquivo appsettings.json vamos definir a string de conexão com o banco SQLite:

{
   "ConnectionStrings": {
                 "Sqlite": "Data Source=products.db"
},
...

A seguir vamos registrar o contexto do banco de dados (AppDbContext) no container DI e configurar para usar o SQLite como provedor de banco de dados na classe Program:

var connectionString = builder.Configuration
                                .GetConnectionString("Sqlite");
builder.Services.AddDbContext<AppDbContext>(
                                 opt => opt.UseSqlite(connectionString));

Ainda na classe Program vamos criar o método CreateDatabase() que vai criar o banco de dados SQLite na primeira execução do projeto:

...
var app = builder.Build();
CreateDatabase(app);
...

app.Run();

static void CreateDatabase(WebApplication app)
{
   var serviceScope = app.Services.CreateScope();
   var dataContext = serviceScope.ServiceProvider.GetService<AppDbContext>();
   dataContext?.Database.EnsureCreated();
}

Agora vamos usar o Blazor Scaffolder para criar os componentes que vão realizar o CRUD usando as configurações acima.

Clique com o botão direito do mouse sobre o projeto e a seguir clique em Add -> New Scaffolded Item

Na janela - Add New Scaffolde Item - selecione a opção Razor Component;

A seguir selecione : Razor Components using Entity Framework (CRUD) e clique no botão Add;

Na janela - Add Razor Components using Entity Framework (CRUD)

Defina as informações conforme mostradas na figura e clique em Add;

Ao final do processo serão criados os componentes Razor dentro da pasta Pages em uma pasta ProductPages:

Vamos incluir no componente NavMenu.razor um link para acessar o componente Index.razor :

...
<div class="nav-item px-3">
     <NavLink class="nav-link" href="products">
          <span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> Products
      </NavLink>
</div>
...

Executando o projeto e teremos o seguinte resultado:


 

Acessando o link Products no menu teremos a exibição dos produtos usando o QuickGrid:

O código do componente Index.razor é visto abaixo:

@page "/products"

<PageTitle>Index</PageTitle>

<h1>Index</h1>

<p>
    <a href="products/create">Create New</a>
</p>

<QuickGrid Class="table" Items="DB.Products">
    <PropertyColumn Property="product => product.Name" />
    <PropertyColumn Property="product => product.Description" />

    <TemplateColumn Context="product">
        <a href="@($"products/edit?id={product.Id}")">Edit</a> |
        <a href="@($"products/details?id={product.Id}")">Details</a> |
        <a href="@($"products/delete?id={product.Id}")">Delete</a>
    </TemplateColumn>
</QuickGrid>

Clicando no link para criar um novo projeto temos o componente Create.razor exibido:

O código do componente é visto a seguir:

@page "/products/create"

<PageTitle>Create</PageTitle>

<h1>Create</h1>

<h4>Product</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <EditForm method="post" Model="Product" OnValidSubmit="AddProduct"
                                                                    FormName="create" Enhance>
            <DataAnnotationsValidator />
            <ValidationSummary class="text-danger" />

            <div class="mb-3">
                <label for="name" class="form-label">Name:</label>
                <InputText id="name" @bind-Value="Product.Name" class="form-control" />
                <ValidationMessage For="() => Product.Name" class="text-danger" />
            </div>       
            <div class="mb-3">
                <label for="description" class="form-label">Description:</label>
                <InputText id="description" @bind-Value="Product.Description" class="form-control" />
                <ValidationMessage For="() => Product.Description" class="text-danger" />
            </div>       
            <button type="submit" class="btn btn-primary">Create</button>
        </EditForm>
    </div>
</div>

<div>
    <a href="/products">Back to List</a>
</div>

@code {

    [SupplyParameterFromForm]
    public Product Product { get; set; } = new();

    public async Task AddProduct()
    {
        DB.Products.Add(Product);
        await DB.SaveChangesAsync();
        NavigationManager.NavigateTo("/products");
    }
}

Vemos aqui o uso do parâmetro Enhance na tag EditForm e o uso do atributo  [SupplyParameterFromForm].

Para visalizar os requests fetchs emitidos pelo script blazor.web.js pressione F12 e na janela do console selecione Rede ou Network e após realizar as operações CRUD teremos o resultado abaixo:

Observe que não temos uma atualização completa da página, mas uma atualização suave graças ao recurso da navegação de formulário aprimorada.

Podemos também remover a interatividade do lado do servidor conforme mostra o código abaixo:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorComponents();
   //.AddInteractiveServerComponents();

...

app.MapRazorComponents<App>();
    //.AddInteractiveServerRenderMode();

app.Run();

 

E mesmo assim nossa aplicação vai continuar funcionando pois temos uma aplicação Blazor usando a renderização estatica no servidor com a capacidade de tratar com formulários e receber parametros de consulta via query string  sem utilizar o modo InteractiveServer ou InteractiveWebAssembly.

Pegue o código do projeto aqui:  BlazorForms.zip ...

"Pois estes mudaram a verdade de Deus em mentira, e honraram e serviram mais a criatura do que o Criador, que é bendito eternamente. Amém."
Romanos 1:25

Referências:


José Carlos Macoratti