ASP .NET Core - CRUD usando Blazor e Entity Framework Core - I


 Hoje vamos criar uma aplicação ASP .NET Core com Blazor e realizar um CRUD básico usando o Entity Framework Core 2.0.     

A Microsoft anunciou recentemente o lançamento de um novo framework web - o Blazor que eu apresentei neste artigo : Blazor - O novo framework SPA da Microsoft - Macoratti

Hoje, vamos criar uma aplicação ASP.NET Core usando o Blazor e o Visual Studio 2017 e realizar um CRUD básico usando os recursos do Entity Framework Core.

Os pré-requisitos necessários são:

Nota: O Blazor não é suportado em versões do Visual Studio anteriores a versão v15.7 e precisa do .NET Core SDK 2.1

Como exemplo eu vou usar um banco de dados já criado no SQL Server com o nome de Cadastro e a tabela Clientes que possui a seguinte estrutura e dados:

 
 

O Script SQL para gerar a tabela Clientes segue abaixo:

USE [Cadastro]
GO
CREATE TABLE [dbo].[Clientes](
	[ClienteId] [int] IDENTITY(1,1) NOT NULL,
	[Nome] [nvarchar](80) NOT NULL,
	[Email] [nvarchar](150) NULL,
	[Pais] [nvarchar](20) NULL
)

Agora mãos à obra...

Criando o projeto ASP .NET Core Blazor no VS 2017

Após esse procedimento abra o VS 2017 Community e selecione File ->New Project;

Selecione .NET Core e o template ASP .NET Core Web Application e informe o nome Blazor_Crud e clique em OK;

Na próxima janela selecione o template Blazor (ASP .NET Core hosted) e clique em OK:

 

Na janela Solution Explorer podemos ver a estrutura do projeto criado conforme mostra a imagem a seguir:

 

Observe que temos 3 projetos criados nesta solução:

  1. BlazorCrud.Client – Possui o código do lado do cliente e contém as páginas que serão renderizadas no navegador.
     
  2. BlazorCrud.Server – Possui o código do lado do servidor, tal como as operações relacionados com o banco de dados e nossa Web API.
     
  3. BlazorCrud.Shared – Possui o código compartilhado que pode ser acessando tanto pelo cliente como pelo servidor.

 

Executando o projeto iremos obter no navegador o seguinte resultado: (que já analisamos neste artigo)

Vemos que nosso projeto esta funcional e apresenta o resultado padrão.

Estas páginas que foram criadas por padrão não irão afetar o nosso aplicativo, mas vamos excluir as páginas Fetchdata e Counter da pasta BlazorCrud.Client /Pages.

Adicionando o modelo de domínio na Aplicação

Clique com o botão direito do mouse sobre o projeto Blazor_Crud.Shared e a seguir selecione Add->New Folder e informe o nome Models.

A seguir crie uma classe chamada Cliente na pasta Models com o código abaixo:

Esta classe contém as propriedades do modelo Cliente que será mapeado para a tabela Clientes.

Observe que estamos usando o atributo [Required] da DataAnnotations. Para isso temos que incluir uma referência ao pacote no projeto via Nuget:

Vamos agora criar nossa camada de acesso a dados.

Criando a camada de acesso a dados da aplicação Blazor

Clique com o botão direito do mouse sobre o projeto Blazor_Crud.Server e a seguir selecione Add->New Folder e informe o nome DataAccess.

A seguir inclua nesta pasta a classe AppDbContext que é a nossa classe de contexto que vai herdar da classe DbContext do Entity Framework Core e inclua o código abaixo nesta classe:

using Blazor_Crud.Shared.Models;
using Microsoft.EntityFrameworkCore;
namespace Blazor_Crud.Server.DataAccess
{
    public class AppDbContext : DbContext
    {
        public virtual DbSet<Cliente> Clientes { get; set; }
        public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
        { }
    }
}

Nesta classe usamos uma referência ao Entity Framework Core para poder herdar da classe DbContext e definir assim a propriedade DbSet<Cliente> que mapeia para a tabela Clientes.

Precisamos agora registrar o contexto como um serviço e definir o provedor do banco de de dados e a string de conexão. Fazemos isso no arquivo Startup do projeto.

Abra o arquivo Startup.cs e inclua o código destacado em azul abaixo:

 public class Startup
 {
        public IConfiguration Configuration { get; }
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<AppDbContext>(options =>
              options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
            services.AddMvc();
            services.AddResponseCompression(options =>
            {
                options.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(new[]
                {
                    MediaTypeNames.Application.Octet,
                    WasmMediaTypeNames.Application.Wasm,
                });
            });
        }
   ....
}

Tivemos criar a propriedade Configuration para poder acessar a string de conexão que foi definida no arquivo appsettings.json. (Como esse arquivo não existe por padrão tivemos também que incluir o arquivo no projeto)

{
  "ConnectionStrings": {
    "DefaultConnection": "Data Source=Macoratti;Initial Catalog=Cadastro;Integrated Security=True"
  }
}

Neste arquivo definimos a string de conexão local do meu SQL Server. (Use a string de conexão do seu ambiente.)

Vamos agora criar a nossa Web API que expõe os serviços para realizar o CRUD usando o EF Core.

Criando a WEB API - Incluindo o Controller ClientesController

Clique com o botão direito sobre a pasta Blazor_Crud.Server/Controllers e selecione Add ->Controller...;

A seguir selecione o template API Controller with actions, using Entity Framework e clique em Add;

A seguir informe o modelo - Cliente -  e o contexto conforme abaixo e clique em Add;

Note que não estamos gerando as views. Vamos fazer isso na segunda parte do artigo.

Inclua o código abaixo no controlador gerado:

using Blazor_Crud.Server.DataAccess;
using Blazor_Crud.Shared.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Blazor_Crud.Server.Controllers
{
    [Produces("application/json")]
    [Route("api/[controller]")]
    [ApiController]
    public class ClientesController : Controller
    {
        private readonly AppDbContext _context;
        public ClientesController(AppDbContext context)
        {
            _context = context;
        }
        // GET: api/Clientes
        [HttpGet]
        public IEnumerable<Cliente> GetClientes()
        {
            return _context.Clientes;
        }
        // GET: api/Clientes/5
        [HttpGet("{id}")]
        public async Task<IActionResult> GetCliente([FromRoute] int id)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            var cliente = await _context.Clientes.FindAsync(id);
            if (cliente == null)
            {
                return NotFound();
            }
            return Ok(cliente);
        }
        // PUT: api/Clientes/5
        [HttpPut("{id}")]
        public async Task<IActionResult> PutCliente([FromRoute] int id, [FromBody] Cliente cliente)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            if (id != cliente.ClienteId)
            {
                return BadRequest();
            }
            _context.Entry(cliente).State = EntityState.Modified;
            try
            {
                await _context.SaveChangesAsync();
            }
            catch (DbUpdateConcurrencyException)
            {
                if (!ClienteExists(id))
                {
                    return NotFound();
                }
                else
                {
                    throw;
                }
            }
            return NoContent();
        }
        // POST: api/Clientes
        [HttpPost]
        public async Task<IActionResult> PostCliente([FromBody] Cliente cliente)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            _context.Clientes.Add(cliente);
            await _context.SaveChangesAsync();
            return CreatedAtAction("GetCliente", new { id = cliente.ClienteId }, cliente);
        }
        // DELETE: api/Clientes/5
        [HttpDelete("{id}")]
        public async Task<IActionResult> DeleteCliente([FromRoute] int id)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            var cliente = await _context.Clientes.FindAsync(id);
            if (cliente == null)
            {
                return NotFound();
            }
            _context.Clientes.Remove(cliente);
            await _context.SaveChangesAsync();
            return Ok(cliente);
        }
        private bool ClienteExists(int id)
        {
            return _context.Clientes.Any(e => e.ClienteId == id);
        }
    }
}

Neste momento a estrutura da nossa solução pode ser vista a seguir:

A lógica do nosso backend esta pronta. Vamos agora definir o código do lado do cliente.

Na próxima parte do artigo vamos definir o código do projeto Blazor_Crud.Client.

 

Referências:


José Carlos Macoratti