ASP .NET Core - Criando sua primeira Web API com ASP .NET Core MVC e VS 2017 - I

 Neste artigo eu vou mostrar como criar uma Web API com ASP .NET Core MVC usando o VS Community 2017.

O protocolo HTTP é uma plataforma poderosa para construir APIs que expõem serviços e dados. O HTTP é simples, flexível e onipresente. Quase toda a plataforma possui uma biblioteca HTTP, assim, os serviços HTTP podem alcançar uma ampla gama de clientes, desde navegadores a dispositivos móveis e aplicações desktop tradicionais.

Neste tutorial, vamos criar uma Web API simples para gerenciar uma lista de itens de "tarefas pendentes", para isso vamos usar os recursos da ASP .NET Core que possui suporte interno para criar Web APIs. (Não vamos criar nenhuma interface neste exemplo)

Nota: Este tutorial foi integralmente baseado no original https://docs.microsoft.com/en-us/aspnet/core/tutorials/first-web-api com pequenos ajustes e traduções.

Para acompanhar este artigo você precisa ter instalado o Visual Studio Community 2017 com os seguintes workloads instalados:

Vamos começar definindo o nosso objetivo e apresentando uma visão geral sobre a API que vamos criar. Abaixo temos um resumo das funcionalidades da Web API que será criada:

API Descrição Request body Response body
GET /api/tarefa Obtém todos os itens None Array de items Tarefa
GET /api/tarefa/{id} Obtém um item pelo id None Item Tarefa
POST /api/tarefa Adiciona um novo item Item Tarefa Item Tarefa
PUT /api/tarefa/{id} Atualiza um item existente    Item tarefa  
DELETE /api/tarefa/{id}     Deleta um item Nada. Sem request body None

O diagrama da figura mostra uma descrição da API :

O client é o quem consome a Web API da Web (pode ser um navegador, um aplicativo para celular e etc.). Não vamos criar um cliente neste tutorial. Usaremos o Postman para testar o aplicativo.

Um model é um objeto que representa os dados em seu aplicativo. Neste caso, o único modelo é um item de tarefa. Os modelos são representados como classes C# simples.(POCOs).

Um controller é um objeto que manipula solicitações HTTP e cria a resposta HTTP. Este aplicativo terá um único controlador.

Para manter o tutorial simples, o aplicativo não usa um banco de dados persistente. Em vez disso, ele armazena itens de tarefas em um banco de dados na memória.

Obs: O Postman é uma aplicação que permite realizar requisições HTTP a partir de uma interface simples e intuitiva, facilitando o teste e depuração de serviços REST. (o Postman é instalado a partir da Chrome Web Store.)

Criando o projeto no VS Community 2017

Abra no VS community 2017 e no menu File clique em New Project;

A seguir selecione o template Visual C# -> .NET Core e marque ASP .NET Core Web Application (.NET Core);

Informe o nome AspnetCore_WebApi e clique no botão OK;

Na próxima janela escolha a versão ASP .NET Core 1.1 e marque o template Web Api sem autenticação e clique no botão OK;

Você terá o seguinte projeto criado:

O Visual Studio utiliza um template padrão para o projeto Web API que é criado e pode ser visto na figura acima.

Temos assim uma aplicação funcional, na verdade , um simples projeto inicial, que é o nosso ponto de partida.

Pressione F5 para rodar a aplicação no modo debug ou Ctrl+F5 para rodar no modo não debug. (O VS inicia o servidor IIS Express e executa a nossa aplicação.)

Observe que o endereço na barra de navegação exibe localhot:1164/api/values já exibindo valores de retorno para uma web api padrão que foi criada.

Adicionando o suporte para o Entity Framework Core

Vamos instalar o Entity Framework Core InMemory database provider que permite usar o Entity Framework Core com um banco de dados em memória.

Ele é útil para testar código que usa Entity Framework Core. O provedor é mantido como parte do projeto EntityFramework GitHub.

Instale o pacote Nuget - Microsoft.EntityFrameworkCore.InMemory NuGet package 

Para isso abra o Package Manager Console via menu Tools e digite o comando : Install -Package Microsoft.EntityFrameworkCore.InMemory

Agora vamos editar o arquivo AspnetCore_WebApi.csproj.

Para isso clique com o botão direito do mouse sobre AspnetCore_WebAPi e selecione : Edit AspnetCore_WebApi.csproj :

A seguir em <ItemGroup> inclua o PackageReference destacado conforme mostra a figura abaixo:

Incluindo um modelo de domínio

Um modelo é um objeto que representa os dados em seu aplicativo. Neste caso, o único modelo é um item de tarefa.

Vamos criar uma pasta chamada "Models" no projeto para nesta pasta definir o modelo.

Na janela Solution Explorer, clique com o botão direito do mouse no projeto e selecione Add -> New Folder e informe o nome Models.

Nota: Você pode colocar classes do modelo em qualquer lugar em seu projeto, mas a pasta Models é usada por convenção.

Agora vamos criar uma classe TarefaItem. Clique com o botão direito do mouse na pasta Models e selecione Add ->Class e atribua o nome TarefaItem à classe e clique em Add.

Substitua o código gerado pelo código abaixo:

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace AspnetCore_WebApi.Models
{
    public class TarefaItem
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public long Chave { get; set; }
        public string Nome { get; set; }
        public bool EstaComplata { get; set; }
    }
}

Destaques do código :

- A anotação de dados [Key] indica a propriedade, Key, que é um identificador exclusivo;
- DatabaseGenerated especifica que o banco de dados gerará a chave (em vez do aplicativo);
- DatabaseGeneratedOption.Identity especifica que o banco de dados deve gerar chaves inteiras quando uma linha for inserida.

Criando o contexto do banco de dados

O contexto do banco de dados é a classe principal que coordena a funcionalidade do Entity Framework para um determinado modelo de dados.

Você cria essa classe derivando da classe Microsoft.EntityFrameworkCore.DbContext.

Nota: A classe DbContext administra os objetos entidades durante o tempo de execução, o que inclui preencher objetos com dados de um banco de dados, controlar alterações, e persistir dados para o banco de dados.

Vamos criar uma classe chamada TarefaContext na pasta Models.

Clique com o botão direito do mouse na pasta Models e selecione Add -> Class e informe o nome TarefaContext e clique no botão Add;

A seguir substitua o código que foi gerado  pelo código abaixo:

using Microsoft.EntityFrameworkCore;
namespace AspnetCore_WebApi.Models
{
    public class TarefaContext : DbContext
    {
        public TarefaContext(DbContextOptions<TarefaContext> options)
            : base(options)
        { }
         public DbSet<TarefaItem> TarefaItens { get; set; }
    }
}

A maneira recomendada para trabalhar com o contexto é definir uma classe que deriva de DbContext e expõe as propriedades de DbSet que representam as coleções das entidades especificadas no contexto.

Uma vez que você tenha um contexto, você iria consultar, adicionar (usando os métodos Add ou Attach) ou remover (usando Remove) as entidades no contexto através destas propriedades.

Acessar uma propriedade DbSet em um objeto de contexto representa uma consulta inicial que retorna todas as entidades do tipo especificado.

Adicionando uma classe Repositório

O padrão de projeto Repository acrescenta uma camada de abstração no topo da camada de consultas e ajuda eliminar lógica duplicada na implementação do código de suas consultas ao modelo de entidades.

Foi Martin Fowler definiu o padrão Repository no seu livro - Patterns of Enterprise Application Architecture - da seguinte forma:"Intermedeia entre o domínio e as camadas de mapeamento de dados usando uma interface de coleção para acessar objetos de domínio." (numa tradução livre by Macoratti)

Assim, um repositório é essencialmente uma coleção de objetos de domínio em memória, e, com base nisso o padrão Repository permite realizar o isolamento entre a camada de acesso a dados (DAL) de sua aplicação e sua camada de apresentação (UI) e camada de negócios (BLL).

Ao utilizar o padrão Repository você pode realizar a persistência e a separação de interesses em seu código de acesso a dados visto que ele encapsula a lógica necessária para persistir os objetos do seu domínio na sua fonte de armazenamento de dados.

Dessa forma o repositório é um objeto que encapsula a camada de acesso a dados e contém a lógica para retornar e mapear os dados para um modelo de entidades.

Vamos implementar o padrão Repository em nossa aplicação, e, a abordagem clássica para fazer isso é criar uma interface contendo os métodos que desejamos expor e a seguir implementar essa interface na classe repositório.

Clique com o botão direito do mouse na pasta Models e selecione Add -> New Item e selecione o template Interface e informe o nome ITarefaRepositorio e clique no botão Add;

A seguir define o código abaixo :

using System.Collections.Generic;
namespace AspnetCore_WebApi.Models
{
    public interface ITarefaRepositorio
    {
        void Add(TarefaItem item);
        IEnumerable<TarefaItem> GetAll();
        TarefaItem Find(long key);
        void Remove(long key);
        void Update(TarefaItem item);
    }
}

Nesta interface estamos definindo métodos para realizar um CRUD básico. Vamos agora implementar essa interface.

Clique com o botão direito do mouse na pasta Models e selecione Add -> Class e informe o nome TarefaRepositorio e clique no botão Add;

A seguir define o código abaixo :

using System.Collections.Generic;
using System.Linq;
namespace AspnetCore_WebApi.Models
{
    public class TarefaRepositorio : ITarefaRepositorio
    {
        private readonly TarefaContext _context;
        public TarefaRepositorio(TarefaContext context)
        {
            _context = context;
            Add(new TarefaItem { Nome = "Item1" });
        }
        public IEnumerable<TarefaItem> GetAll()
        {
            return _context.TarefaItens.ToList();
        }
        public void Add(TarefaItem item)
        {
            _context.TarefaItens.Add(item);
            _context.SaveChanges();
        }
        public TarefaItem Find(long key)
        {
            return _context.TarefaItens.FirstOrDefault(t => t.Chave == key);
        }
        public void Remove(long key)
        {
            var entity = _context.TarefaItens.First(t => t.Chave == key);
            _context.TarefaItens.Remove(entity);
            _context.SaveChanges();
        }
        public void Update(TarefaItem item)
        {
            _context.TarefaItens.Update(item);
            _context.SaveChanges();
        }
    }
}

No código acima temos a implementação dos métodos definidos na interface ITarefaRepositorio.

O contexto de banco de dados é definido em uma variável de classe (_context) , e o construtor espera o objeto de chamada para passar em uma instância do contexto. Aqui estamos passando a instância TarefaContext para o construtor.

O código usa os recursos do Entity Framework para realizar as operações definidas na interface ITarefaRepositorio.

Registrando o Repositório (usando o contâiner DI)

Ao definir uma interface repositório, podemos desacoplar a classe de repositório do controlador MVC que a utiliza. Ao invés de instanciar uma classe TarefaRepositorio dentro do controlador, injetaremos uma interface ITarefaRepositorio usando o suporte interno no ASP.NET Core para injeção de dependência.

Esta abordagem facilita os testes unitários dos controladores. Os testes de unidade devem injetar uma versão simulada ou stub de ITarefaRepositorio. Dessa forma, o teste segmenta de forma restrita a lógica do controlador e não a camada de acesso a dados.

Para injetar o repositório no controlador, precisamos registrá-lo com o contâiner DI.

Abra o arquivo Startup.cs do projeto e no método ConfigureServices(), adicione o código em azul em destaque:

using AspnetCore_WebApi.Models;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
...
public class Startup
{
       ...
     // This method gets called by the runtime. Use this method to add services to the container.
     public void ConfigureServices(IServiceCollection services)
     {
            // Add framework services.
            services.AddMvc();
            services.AddSingleton<ITarefaRepositorio, TarefaRepositorio>();
     }
   ...
}

O método ConfigureServices() é responsável por definir os serviços que a aplicação vai usar, incluindo recursos da plataforma como ASP .NET Core MVC e Entity Framework.

Na implementação da Injeção de dependência do ASP.NET Core, vemos o conceito de lifetimes ou "tempo de vidas". Um lifetime ou tempo de vida especifica quando um objeto DI-injetado é criado ou recriado. Existem três possibilidades:

  1. - Transient : Criado a cada vez que são solicitados.
  2. - Scoped: Criado uma vez por solicitação.
  3. - Singleton: Criado na primeira vez que são solicitados. Cada solicitação subseqüente usa a instância que foi criada na primeira vez.

O parâmetro IServiceCollection permite configurar diferentes tipos de serviços seja por criação de objeto ou correspondência a uma interface específica e suporta os lifetimes mencionados.

No exemplo estamos adicionando um serviço Singleton.

Incluindo um Controller no projeto

Se você não sabe o que é um Controller então pode ler os seguintes artigos  :

Os Controllers ou Controladores são os componentes que lidam com a interação do usuário, trabalham com o modelo e, finalmente, selecionam uma exibição de renderização que mostra essa interface ao usuário. Por padrão os controladores são colocados na pasta Controllers da solução.

Clique com o botão direito do mouse na pasta Controllers e selecione Add -> New Item;

A seguir selecione o template Web API Controller Class e informe o nome TarefaController e clique no botão Add;

Agora substitua o código gerado pelo código abaixo na classe TarefaController:

using AspnetCore_WebApi.Models;
using Microsoft.AspNetCore.Mvc;
namespace AspnetCore_WebApi.Controllers
{
    [Route("api/[controller]")]
    public class TarefaController : Controller
    {
        private readonly ITarefaRepositorio _tarefaRepositorio;
        public TarefaController(ITarefaRepositorio tarefaRepositorio)
        {
            _tarefaRepositorio = tarefaRepositorio;
        }
       [HttpGet]
       public IEnumerable<TarefaItem> GetAll()
       {
            return _tarefaRepositorio.GetAll();
       }

       [HttpGet("{id}", Name = "GetTarefa")]
       public IActionResult GetById(long id)
       {
           var item = _tarefaRepositorio.Find(id);
           if (item == null)
           {
                 return NotFound();
           }
          return new ObjectResult(item);
       }
    }
}

O código temos a implementação de dois métodos GET :

O atributo [HttpGet] especifica um método HTTP GET e o caminho da URL para cada método é construido da seguinte maneira:

No método GetById temos que :


        [HttpGet("{id}", Name = "GetTarefa")]
       public IActionResult GetById(long id)
       {
           .....
       }

Vamos entender esse trecho de código :

- "{id}" é uma variável de espaço reservado para o ID do item tarefa. Quando o método GetById for chamado, ele atribuirá o valor de "{id}" na URL para o parâmetro id do método.

- Name = "GetTarefa" cria uma rota nomeada e permite que você vincule a esta rota uma Resposta HTTP.

O método GetAll retorna um IEnumerable e o MVC automaticamente serializa o objeto para JSON e escreve o JSON no corpo da mensagem response. O código response para este método é 200, assumindo que não existam exceções não tratadas. (Exceções não tratadas são traduziadas em erros 5xx)

Em contraste o método GetById retorna um tipo IActionResult, o que representa um ampla variedade de tipos de retornos. GetById possui dois tipos de retornos diferentes:

  1. Se nenhum item coincidir com o ID requisitado, o método retorna o erro 404. Isto é feito no código pelo retorno de NotFound.

  2. Se houver correspondência com o ID requisistado, o método retorna 200 com um JSON no corpo do response. Isto é feito no código pelo retorno de um ObjectResult.

Agora podemos testar. Pressione Ctrl+F5 para rodar a aplicação.

O Visual Studio vai iniciar o navegador e navegar para http://localhost:porta/api/values   onde: porta é um valor escolhido aleatoriamente

O navagador deve exibir o seguinte resultado:

Não estamos usando ainda nenhum método do controlador TarefaController.

Na próxima parte do artigo vamos implementar os métodos CRUD.

Considerai os corvos, que nem semeiam, nem segam, nem têm despensa nem celeiro, e Deus os alimenta; quanto mais valeis vós do que as aves? Lucas 12:24

Veja os Destaques e novidades do SUPER DVD Visual Basic (sempre atualizado) : clique e confira !

Quer migrar para o VB .NET ?

Quer aprender C# ??

Quer aprender os conceitos da Programação Orientada a objetos ?

Quer aprender o gerar relatórios com o ReportViewer no VS 2013 ?

  Gostou ?   Compartilhe no Facebook   Compartilhe no Twitter

Referências:


José Carlos Macoratti