Angular 9 - CRUD com ASP .NET Core WEB API 3.1


Vamos implementar uma aplicação ASP .NET Core Web API usando a versão 3.1 e realizar as operações CRUD usando o Angular 9.

Neste tutorial vamos iniciar criando um projeto exemplo para tratar dos detalhes de pagamentos de um cartão de Crédito.

recursos usados:

  • VS 2019 Community 16.6.2
  • Angular 9

Criando uma WEB API com ASP .NET Core

Abra o VS 2019 Community e crie um novo projeto( File-> New Project ) ;

Selecione o template ASP .NET Core Web Application, e, Informe o nome Api_Cartao;

A seguir selecione .NET Core e ASP .NET Core 3.1 e marque o template API e as configurações conforme a figura abaixo:

Clicando no botão Create teremos o projeto criado e pronto para ser ajustado onde vamos remover os arquivos que não iremos usar no projeto.

Configurando o banco de dados

Vamos criar um banco de dados para este projeto e vamos usar o Entity Framework Core para realizar as operações com o  banco de dados.

Para isso vamos instalar os seguintes pacotes Nuget para referênciar as referências do  Entity FrameworkCore:

  • Microsoft.EntityFrameworkCore.SqlServer (3.1.5)
  • Microsoft.EntityFrameworkCore.Tools (3.1.5)

Repita os procedimentos abaixo para cada pacote:

  • Clique com o botão direito do mouse no nome do Projeto na janela Solution Explorer;
  • Clique em Manage Nuget Package;
  • Selecione a guia Browse e informe o nome do pacote a ser instalado;
  • Marque os projetos onde deseja instalar e clique em Install;

Crie na raiz do projeto a pasta Models e nesta pasta crie a classe Pagamento que vai representar a entidade do nosso modelo de domínio anêmico:

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace ApiCartao.Models
{
    public class Pagamento
    {
        public int PagamentoId { get; set; }
        [Required]
        [Column(TypeName = "nvarchar(100)")]
        public string NomeTitular { get; set; }
        [Required]
        [Column(TypeName = "varchar(16)")]
        public string NumeroCartao { get; set; }
        [Required]
        [Column(TypeName = "varchar(5)")]
        public string DataExpiracao { get; set; }
        [Required]
        [Column(TypeName = "varchar(3)")]
        public string CVV { get; set; }
    }
}

Na mesma pasta Models crie o arquivo AppDbContext que representa o nosso arquivo de contexto que vai herdar de DbContext e permitir a comunicação entre o EF Core o banco de dados:

using Microsoft.EntityFrameworkCore;
namespace ApiCartao.Models
{
    public class AppDbContext : DbContext
    {
        public AppDbContext(DbContextOptions<AppDbContext> options) :
            base(options)
        { }

        public DbSet<Pagamento> Pagamentos { get; set; }
    }
}

A classe AppDbContext decide o que deve ser adicionado ao banco de dados físico durante a migração do banco de dados. Para isso, adicionamos a propriedade DbSet à classe Pagamento, assim, após a migração,  a tabela Pagamentos e a base de dados serão criados no SQL Server.

No parâmetro options do construtor da classe, temos que passar qual o provedor do banco de dados (SQL Server, MySQL, PostgreSQL, etc) vamos usar e informar a string de conexão.

Para isso, usaremos a injeção de dependência no arquivo Startup do projeto fazendo o registro do serviço:

 public void ConfigureServices(IServiceCollection services)
 {
       services.AddDbContext<AppDbContext>(optionns =>
           optionns.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
            services.AddControllers();
 }

Podemos ainda habilitar o CORS incluindo no método ConfigureServices:

 public void ConfigureServices(IServiceCollection services)
 {
       services.AddDbContext<AppDbContext>(optionns =>
           optionns.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
       services.AddCors(options =>
            {
                options.AddPolicy("CorsPolicy",
                    builder => builder
                   .AllowAnyMethod()
                   .AllowAnyHeader()
                   .SetIsOriginAllowed((host) => true)
                   .AllowCredentials());
            });
            services.AddControllers();
 }

Isso é importante para permitir as requisições que serão feitas pela aplicação Angular do endereço localhost:4200.

E no método Configure incluir o código a seguir:

 public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            app.UseRouting();           
            app.UseCors("CorsPolicy");
            app.UseStaticFiles();
            app.UseAuthorization();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }

Precisamos ainda definir no arquivo appsettings.json a string de conexão definida com o nome DefaultConnection:

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

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

Pronto, já podemos aplicar o Migrations emitindo os comandos abaixo na janela do Package Manager Console :

add-migration inicial
update-database

Ao final teremos o banco de dados PagamentoCartaoDB.mdf e a tabela Pagamentos criados no SQL Server.

Criando a API para as operações CRUD

Vamos criar o controlador PagamentosController na pasta Controllers do projeto usando o Scaffold.

Para isso clique com o botão direito do mouse sobre a pasta Controllers e clique em  Add->Controller;

A seguir selecione a opção : API Controller with actions, using Entity Framework e clique em Add;

A seguir informe os dados na janela Add API Controller with.. conforme abaixo

Clique no botão Add para criar o controlador PagamentosController:

using ApiCartao.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace ApiCartao.Controllers
{
    [Route("api/[controller]")]
    [Produces("application/json")]
    [ApiController]
    public class PagamentosController : ControllerBase
    {
        private readonly AppDbContext _context;
        public PagamentosController(AppDbContext context)
        {
            _context = context;
        }
        // GET: api/Pagamentos
        [HttpGet]
        public async Task<ActionResult<IEnumerable<Pagamento>>> GetPagamentos()
        {
            return await _context.Pagamentos.ToListAsync();
        }
        // GET: api/Pagamentos/5
        [HttpGet("{id}")]
        public async Task<ActionResult<Pagamento>> GetPagamento(int id)
        {
            var pagamento = await _context.Pagamentos.FindAsync(id);
            if (pagamento == null)
            {
                return NotFound();
            }
            return pagamento;
        }
        // PUT: api/Pagamentos/5
        [HttpPut("{id}")]
        public async Task<IActionResult> PutPagamento(int id, Pagamento pagamento)
        {
            if (id != pagamento.PagamentoId)
            {
                return BadRequest();
            }
            _context.Entry(pagamento).State = EntityState.Modified;
            try
            {
                await _context.SaveChangesAsync();
            }
            catch (DbUpdateConcurrencyException)
            {
                if (!PagamentoExists(id))
                {
                    return NotFound();
                }
                else
                {
                    throw;
                }
            }
            return NoContent();
        }
        // POST: api/Pagamentos
        [HttpPost]
        public async Task<ActionResult<Pagamento>> PostPagamento(Pagamento pagamento)
        {
            _context.Pagamentos.Add(pagamento);
            await _context.SaveChangesAsync();
            return CreatedAtAction("GetPagamento", new { id = pagamento.PagamentoId }, pagamento);
        }
        // DELETE: api/Pagamentos/5
        [HttpDelete("{id}")]
        public async Task<ActionResult<Pagamento>> DeletePagamento(int id)
        {
            var pagamento = await _context.Pagamentos.FindAsync(id);
            if (pagamento == null)
            {
                return NotFound();
            }
            _context.Pagamentos.Remove(pagamento);
            await _context.SaveChangesAsync();
            return pagamento;
        }
        private bool PagamentoExists(int id)
        {
            return _context.Pagamentos.Any(e => e.PagamentoId == id);
        }
    }
}

Acima temos o código gerado pelo Scaffolding onde vemos os métodos da Web POST, GET, PUT e DELETE para operações de criação, recuperação, atualização e exclusão, respectivamente.

Aqui estamos injetando uma instância do nosso contexto AppDbContext no construtor para poder realizar as operações com as entidades e persistir no banco de dados via EF Core.

Estamos seguindo as práticas para as API REST e estamos forçando a nossa API a retornar JSON. Assim não precisamos alterar os métodos HTTP gerados e podemos inclusive testar as operações CRUD usando um software como o Postman.

Ao final temos os seguintes endpoints definidos:

GET /api/Pagamentos/          - Recupera todos os registros
GET /api/Pagamentos/id       - Recupera um registro com o ID fornecido
POST /api/Pagamentos/        - Criar um novo registro
PUT /api/Pagamentos/id       - Atualiza um registro com o ID fornecido
DELETE /api/Pagamentos/id  - Exclui um registro com o ID fornecido

Nota:  Um endpoint é, de forma simplificada, a URL que monta o caminho para fazer a requisição;

Encerramos aqui a parte da criação da API.

Apenas para fazer um teste para o GET executando o projeto teremos o resultado a seguir:

Se você quiser melhorar o código desacoplando o controlador do EF Core basta criar um repositório, definir uma interface a sua implementação e a seguir injetar a instância do repositório no controlador ao invés de usar diretamente o contexto.

Isso eu vou deixar como um exercício para você, afinal é um conceito que todo o desenvolvedor deve ter.

Na próxima parte do artigo vamos criar a aplicação Angular.

Pegue o projeto aqui : ApiCartao.zip (sem as referências)

"Porque o reino de Deus não é comida nem bebida, mas justiça, e paz, e alegria no Espírito Santo."
Romanos 14:17

Referências:

  • Macoratti .net | Facebook

  • macoratti - YouTube

  • Jose C Macoratti (@macorati) | Twitter

  • Angular 7 - Consumindo Web API ASP .NET MVC - Macoratti.net

  • ASP.NET MVC - Usando o AngularJS - I - Macoratti.net

  • ASP .NET Core e Angular 2 - Criando uma ... - Macoratti.net

  • Angular - Apresentando Material Design - Macoratti.net

  • Criando uma aplicação com Angular CLI - Macoratti.net

  • Angular 7 - Consumindo Web API ASP .NET Core - Macoratti.net

  • Angular 2 - Criando sua primeira aplicação no ... - Macoratti.net


José Carlos Macoratti