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:
- Executa em desempenho quase nativo;
- É executado em uma caixa de areia segura para a memória;
- 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
- Baixe e instale o .NET Core 2.1 SDK (2.1.300 ou posterior).
- 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.
Um grande abraço!