Skip to main content

Nesse artigo mostro um tutorial com exemplo de como utilizar o C# com WebAssembly por meio do Blazor. Mas, antes…

O que é Blazor?

É um framework para aplicações “client-side” escrito em .NET e rodando em cima do WebAssembly.
É baseado em tecnologias já existentes como HTLM e CSS, mas você pode usar C# e Razor ao invés de JavaScript para buildar os componentes. Oferece todos os benefícios de uma plataforma de aplicativo de página única (SPA) rica e moderna ao usar o .NET de ponta a ponta.
A ideia sobre o Blazor é ser capaz de combinar Razor e C # em um projeto da web do lado do cliente que roda completamente no navegador.

O que é WebAssembly?

WebAssembly é um formato binário para o código no navegador e é executado muito mais rápido do que o JavaScript tradicional. Oferece ao navegador várias vantagens, como:

  1. Executa em desempenho quase nativo;
  2. É executado em uma caixa de areia segura para a memória;
  3. Compila a partir de uma variedade de linguagens, ou seja, .NET, C, C++, Java, Rust etc.

A principal vantagem do WebAssembly é que ele lida muito bem com trabalhos com muita memória e multithreading, em comparação com o JavaScript.

Features

O Blazor contém todos os recursos de uma estrutura web moderna, como:

  • Um modelo de componente para a construção de IU combinável;
  • Roteamento;
  • Layouts;
  • Formulários e validação;
  • Injeção de dependência;
  • Recarregamento ao vivo no navegador durante o desenvolvimento;
  • Renderização do lado do servidor;
  • Depuração completa do .NET em navegadores e no IDE;
  • Rich IntelliSense e ferramentas;
  • Publicação e corte de tamanho de aplicativo.

Setup

  1. Baixe e instale o .NET Core 2.1 SDK (2.1.300 ou posterior).
  2. Baixe e instale o Visual Studio 2017 (15.7 ou posterior) com o ASP.NET e a carga de trabalho de desenvolvimento da web selecionados.

Fonte: RIP Tutorial

Um CRUD simples utilizando Blazor, EF Core e in-memory database

Neste exemplo vou lhes mostrar como fazer um simples CRUD utilizando as seguintes ferramentas:

Após a instalação do Blazor, vamos criar um projeto através do seguinte comando:

1
2
dotnet new blazorserver -o <VOCE_ESCOLHE_O_NOME> --no-https
cd NOME_QUE_VOCE_ESCOLHEU

Observação: você pode utilizar o Visual Studio e criar o projeto através do caminho “File > New Solution” e pesquisar por “Blazor”

Para saber se está tudo OK, basta digitar o comando:

1
dotnet run

Por padrão, já vem criada uma aplicação para você se ambientar com o Blazor. Para visualizar a aplicação, acesse http://localhost:5000.

Agora, vamos criar as nossas classes, páginas e instalar alguns pacotes necessários para fazermos o CRUD.

Setup

Primeiro, vamos instalar o pacote Microsoft.EntityFrameworkCore.InMemory. Para isso, digite o seguinte comando (dentro da pasta do seu projeto):

1
dotnet add package Microsoft.EntityFrameworkCore.InMemory --version 3.1.8

Codificando

Agora, dentro da pasta “Data”, vamos criar as seguintes classes: “Context.cs” e “ClienteService.cs”.

A classe “ClienteService.cs” terá o seguinte código:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
using Blazor.Client.Data;
using Blazor.Client.Models;
using System.Collections.Generic;
using System.Threading.Tasks;
 
namespace Blazor.Data
{
    public class ClienteService
    {
        readonly Context _context = new Context();
 
        /// <summary>
        /// Add cliente to the memory database
        /// </summary>
        /// <param name="cliente">The Cliente object</param>
        public async Task AddAsync(Cliente cliente)
        {           
            await Task.Run(() => _context.Clientes.Add(cliente));
 
            SaveChanges();
 
        }
 
        /// <summary>
        /// Add cliente to the memory database
        /// </summary>
        /// <param name="cliente">The Cliente object</param>
        public void Add(Cliente cliente)
        {
            _context.Clientes.Add(cliente);           
            SaveChanges();
 
        }
 
        /// <summary>
        /// Get all Clientes from memory database
        /// </summary>
        /// <returns>A list of all Clientes</returns>
        public async Task<IEnumerable<Cliente>> GetAllAsync()
        {
            List<Cliente> retorno;
 
            return await Task.Run(() => retorno =  new List<Cliente>(_context.Clientes));
             
        }
 
        /// <summary>
        /// Get all Clientes from memory database
        /// </summary>
        /// <returns>A list of all Clientes</returns>
        public IEnumerable<Cliente> GetAll()
        {
            List<Cliente> retorno = new List<Cliente>(_context.Clientes);
 
            return retorno;
 
        }
 
        /// <summary>
        /// Get the Cliente by its ID
        /// </summary>
        /// <param name="id">An integer ID</param>
        /// <returns></returns>
        public Cliente GetById(int id)
        {
            var query = _context.Clientes.Find(id);
 
            return query;
        }
 
        /// <summary>
        /// Get the Cliente by its ID
        /// </summary>
        /// <param name="id">An integer ID</param>
        /// <returns></returns>
        public async Task<Cliente> GetByIdAsync(int id)
        {
            Cliente cliente;
 
            return await Task.Run(() => cliente = _context.Clientes.Find(id));
        }
 
        /// <summary>
        /// Update the Cliente on memory database
        /// </summary>
        /// <param name="cliente">The Cliente object</param>
        public void Update(Cliente cliente)
        {
            _context.Clientes.Update(cliente);
            SaveChanges();
        }
 
        /// <summary>
        /// Update the Cliente on memory database
        /// </summary>
        /// <param name="cliente">The Cliente object</param>
        public async Task UpdateAsync(Cliente cliente)
        {
            await Task.Run(() => _context.Clientes.Update(cliente));
 
            SaveChanges();
        }
 
        /// <summary>
        /// Delete the Client on memory database
        /// </summary>
        /// <param name="cliente">The Cliente object</param>
        public void Delete(Cliente cliente)
        {
            _context.Clientes.Remove(cliente);
            SaveChanges();
        }
 
        /// <summary>
        /// Delete the Client on memory database
        /// </summary>
        /// <param name="cliente">The Cliente object</param>
        public async Task DeleteAsync(Cliente cliente)
        {
            await Task.Run(() => _context.Clientes.Remove(cliente));
 
            SaveChanges();
        }
 
        private int SaveChanges()
        {
            return _context.SaveChanges();
        }
    }
}

A classe “Context.cs” terá o seguinte código:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
using Blazor.Client.Models;
using Microsoft.EntityFrameworkCore;
 
namespace Blazor.Client.Data
{
    public class Context : DbContext
    {       
        public DbSet<Cliente> Clientes { get; set; }
 
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            base.OnConfiguring(optionsBuilder);
            optionsBuilder.UseInMemoryDatabase("BlazorDB");
        }
 
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Cliente>()
                .HasKey(c => c.Id);
 
        }
    }
}

Agora, dentro da pasta “Models”, vamos criar a seguinte classe:

A classe “Model.cs” terá o seguinte código:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
 
namespace Blazor.Client.Models
{
    public class Cliente
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int Id { get; set; }
 
        [Required(ErrorMessage = "Por favor, preencha o nome!")]
        [StringLength(60, MinimumLength = 4,
            ErrorMessage = "O nome deve ter no minimo 4 e no maximo 60 caracteres!")]
        [DisplayName("Nome")]
        public string Nome { get; set; }
 
        [Required(ErrorMessage = "Por favor, preencha o RG!")]
        [StringLength(9)]
        [DisplayName("RG")]
        public string Rg { get; set; }
 
        [Required(ErrorMessage = "Por favor, preencha o CPF!")]
        [StringLength(11, ErrorMessage = "O CPF deve conter 11 digitos")]
        [DisplayName("CPF")]
        public string Cpf { get; set; }
 
        [Required(ErrorMessage = "Por favor, preencha o Endereco!")]
        [StringLength(60)]
        [DisplayName("Endereco")]
        public string Endereco { get; set; }
 
        [Required(ErrorMessage = "Por favor, preencha o Telefone!")]
        [StringLength(11)]
        [DisplayName("Telefone")]
        public string Telefone { get; set; }
 
        [Required(ErrorMessage = "Por favor, preencha o Celular!")]
        [StringLength(12)]
        [DisplayName("Celular")]
        public string Celular { get; set; }
 
        [Required(ErrorMessage = "Por favor, preencha o email!")]
        [EmailAddress(ErrorMessage = "Email invalido!")]
        [StringLength(60)]
        [DisplayName("Email")]
        public string Email { get; set; }
 
    }
}

Agora, dentro da pasta “Pages”, vamos criar a pasta “Clientes” e dentro dela as seguintes páginas: “Cadastrar.razor” e “Editar.razor”.
Ainda na pasta “Pages”, vamos criar a página “Cliente.razor”:

A página “Cadastrar.razor” terá o seguinte código:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
@page "/Clientes/cadastrar"
@using Blazor.Data
@using Models = Blazor.Client.Models
 
@inject ClienteService Service
@inject IJSRuntime JSRuntime
@inject NavigationManager NavigationManager
 
<h3>Cadastrar Clientes</h3>
 
<div class="container">
    <h1 class="text-center">Cadastro de Clientes</h1>
    <div class="row" style="padding-top: 10%">
        <div class="col-lg-12">
            <div class="form-group-lg">
                 
                <EditForm class="text-center" Model="@_cliente">
                    <DataAnnotationsValidator />
                    <ValidationSummary />
                    <div class="row">
                        <div class="col-lg-6">
                            <label id="Nome"> Nome:</label>
                            <InputText id="Nome" @bind-Value="@_cliente.Nome" class="form-control" />
                            <span class="text-danger" style="font-size:small;"></span>
                        </div>
                        <div class="col-lg-6">
                            <label id="Rg">RG:</label>
                            <InputText id="Rg" @bind-Value="@_cliente.Rg" class="form-control" />
                            <span class="text-danger" style="font-size:small;"></span>
                        </div>
                    </div>
 
                    <div class="row">
                        <div class="col-lg-6">
                            <label id="Cpf">CPF:</label>
                            <InputText id="Cpf" @bind-Value="@_cliente.Cpf" class="form-control" />
                            <span class="text-danger" style="font-size:small;"></span>
                        </div>
 
                        <div class="col-lg-6">
                            <label id="Endereco">Endereço:</label>
                            <InputText id="Endereco" @bind-Value="@_cliente.Endereco" class="form-control" />
                            <span class="text-danger" style="font-size:small;"></span>
                        </div>
                    </div>
 
                    <div class="row">
 
                        <div class="col-lg-6">
                            <label id="Telefone">Telefone:</label>
                            <InputText id="Telefone" @bind-Value="@_cliente.Telefone" class="form-control" />
                            <span class="text-danger" style="font-size:small;"></span>
                        </div>
 
                        <div class="col-lg-6">
                            <label id="Celular">Celular:</label>
                            <InputText id="Celular" @bind-Value="@_cliente.Celular" class="form-control" />
                            <span class="text-danger" style="font-size:small;"></span>
                        </div>
                    </div>
 
                    <div class="row">
                        <div class="col-lg-6">
                            <label id="Email">E-mail:</label>
                            <InputText id="Email" @bind-Value="@_cliente.Email" class="form-control" />
                            <span class="text-danger" style="font-size:small;"></span>
                        </div>
 
                        <div class="col-lg-6">
                            <br />
                            <br />
                            <input type="submit" value="Cadastrar" class="btn btn-primary" @onclick="OpenModal" />
                        </div>
                    </div>
 
                </EditForm>
 
            </div>
 
        </div>
    </div>
 
</div>
 
@code {
 
    private Models.Cliente _cliente = new Models.Cliente();
    private int idCount = 0;
 
 
    /// <summary>
    /// It opens the JS alert with a message
    /// </summary>
    /// <returns>void</returns>
    public async Task OpenModal()
    {
        await JSRuntime.InvokeAsync<string>(
 
           "jsFunctions.openModalCadastro", null);
 
        AddCliente();
 
    }
 
    private void AddCliente()
    {
        _cliente.Id = idCount++;
        Service.Add(_cliente);
 
        NavigationManager.NavigateTo("cliente");
    }
 
 
}

E a página “Editar.razor” terá o seguinte código:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
@page "/Clientes/editar/{Id:int}"
@using Blazor.Data
@using Models = Blazor.Client.Models
 
@inject ClienteService Service
@inject IJSRuntime JSRuntime
@inject NavigationManager NavigationManager
 
<h3>Cadastrar Clientes</h3>
 
<div class="container">
    <h1 class="text-center">Cadastro de Clientes</h1>
    <div class="row" style="padding-top: 10%">
        <div class="col-lg-12">
            <div class="form-group-lg">
                <EditForm class="text-center" Model="@_cliente">
 
                    <div class="row">
                        <div class="col-lg-6">
                            <label id="Nome"> Nome:</label>
                            <InputText id="Nome" @bind-Value="@_cliente.Nome" class="form-control" />
                            <span class="text-danger" style="font-size:small;"></span>
                        </div>
                        <div class="col-lg-6">
                            <label id="Rg">RG:</label>
                            <InputText id="Rg" @bind-Value="@_cliente.Rg" class="form-control" />
                            <span class="text-danger" style="font-size:small;"></span>
                        </div>
                    </div>
 
                    <div class="row">
                        <div class="col-lg-6">
                            <label id="Cpf">CPF:</label>
                            <InputText id="Cpf" @bind-Value="@_cliente.Cpf" class="form-control" />
                            <span class="text-danger" style="font-size:small;"></span>
                        </div>
 
                        <div class="col-lg-6">
                            <label id="Endereco">Endereço:</label>
                            <InputText id="Endereco" @bind-Value="@_cliente.Endereco" class="form-control" />
                            <span class="text-danger" style="font-size:small;"></span>
                        </div>
                    </div>
 
                    <div class="row">
 
                        <div class="col-lg-6">
                            <label id="Telefone">Telefone:</label>
                            <InputText id="Telefone" @bind-Value="@_cliente.Telefone" class="form-control" />
                            <span class="text-danger" style="font-size:small;"></span>
                        </div>
 
                        <div class="col-lg-6">
                            <label id="Celular">Celular:</label>
                            <InputText id="Celular" @bind-Value="@_cliente.Celular" class="form-control" />
                            <span class="text-danger" style="font-size:small;"></span>
                        </div>
                    </div>
 
                    <div class="row">
                        <div class="col-lg-6">
                            <label id="Email">E-mail:</label>
                            <InputText id="Email" @bind-Value="@_cliente.Email" class="form-control" />
                            <span class="text-danger" style="font-size:small;"></span>
                        </div>
 
                        <div class="col-lg-6">
                            <br />
                            <br />
                            <input type="submit" value="Editar" class="btn btn-primary" @onclick="OpenModal" />
                        </div>
                    </div>
 
                </EditForm>
 
            </div>
 
        </div>
    </div>
 
</div>
 
@code {
 
    private Models.Cliente _cliente;
 
 
    [Parameter]
    public int Id { get; set; }
 
    protected override async Task OnInitializedAsync()
    {
        _cliente = Service.GetById(Id);
    }
 
    public async Task OpenModal()
    {
        await JSRuntime.InvokeAsync<string>(
 
           "jsFunctions.openModalEdit", null);
 
        EditarCliente();
 
    }
 
    private void EditarCliente()
    {
         
        Service.Update(_cliente);
 
        NavigationManager.NavigateTo("cliente");
 
    }
 
}

Repare que em ambas as páginas temos códigos C# escritos dentro do bloco “@code”. Dentro desse bloco é possível criar qualquer código em C#.

Testando

Após realizar a codificação, rode o comando “dotnet build” para buildar a aplicação. Caso apareça algum erro, leia-o atentamente e verifique os passos anteriores deste artigo.

Deu tudo certo? Então, vamos rodar nossa aplicação:
dotnet run

Essa é a nossa página inicial:

Você pode navegar pelas páginas através do menu no lado esquerdo.

Nossa página “Clientes” está vazia:

Vamos cadastrar alguns clientes:

Agora, nossa página de “Clientes” foi preenchida:

Repare que podemos editar e excluir o dado cadastrado.
Vamos, primeiro, editar:

Agora, vamos excluí-lo:

We made it!

Todas as funções desse CRUD estão na classe “ClienteService.cs”. Lembra do bloco “@code” dentro das páginas “.razor”? Pois bem, é nesse bloco que chamamos as funções da nossa classe.

Este foi um pequeno exemplo de como utilizar o C# com WebAssembly através do Blazor. Espero que tenham gostado.

Qualquer dúvida, crítica ou sugestão, deixe nos comentários.

Acesse o código no Github.

Um grande abraço!

João Paulo de Castro Lima – Analista de Sistemas na BRQ

Sobre o Autor
  • Redação BRQ

    Desde 1993 no mercado, a BRQ Digital Solutions se consolidou como líder e uma das maiores empresas de Transformação digital do país.

    Ver todos os posts