Este artigo é parte da série:
Para esta etapa do projeto, vamos criar um novo controller, chamado “DadosController” na pasta “Controllers”. Atente-se ao detalhe que é uma “API Controlller” e não “MVC Controller” conforme vem no padrão.
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace Treino_REST_02.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class ADOMetodoController : ControllerBase
{
}
}
E vamos começar colocando um nome na nova rota. Neste exercício, vamos chamar de “Dados”.
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace Treino_REST_02.Controllers
{
[Route("api/Dados")]
[ApiController]
public class DadosController : ControllerBase
{
}
}
A rotina que fizemos para o código “BasicoAPIController” possui todas a operações de CRUD (Create, Retrieve, Update, Delete) sendo executadas contra um listagem interna, em memória. O que vamos fazer agora e copiar todos os métodos daquela classe e remover os conteúdos dos métodos. E escrever novos conteúdos, desta vez realizando a operações de CRUD contra um banco de dados.
Esse controller “Dados” não vai fazer nada. Neste momento vai ser apenas um esqueleto para escrevermos os métodos de acesso a dados que virão nos próximos exercício. Por isso vamos deixar propositalmente os conteúdos dos métodos vazios.
Alguns cuidados que foram tomados ao copiar e colar o código:
- Trocar o nome em [Route].
- Trocar os nomes nos métodos, para evitar o conflito com a classe existente. Todos os métodos ganharam um “-Dados” ao final de seus nomes.
- Inserir retorno em todos os métodos, nem que seja “BadRequest” para que este código vazio não apresente erro.
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Treino_REST_02.Models; namespace Treino_REST_02.Controllers { /// <summary> /// Esqueleto para realizar operações CRUD. /// </summary> [Route("api/Dados")] [ApiController] public class DadosController : ControllerBase { IConfiguration Config; public List<UF> UFs = new List<UF>(); /// <summary> /// Construtor inicia objeto Config /// </summary> /// <param name="_config"></param> public DadosController(IConfiguration _config) { this.Config = _config; } /// <summary> /// Relação de todas as UFs com suas capitais /// </summary> /// <returns></returns> [HttpGet(Name = "ListaUF-Dados")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult<IEnumerable<UF>> ListaUF() { return Ok(UFs); } /// <summary> /// Mostra os dados de uma UF específica /// </summary> /// <remarks> /// Caso o id não exista, retorna 404 Not Found. Caso id seja zero retorna Bad Request. /// </remarks> /// <param name="IdUF">Id da UF que será mostrada</param> /// <returns>Um JSON contendo os dados da UF selecionada.</returns> [HttpGet("{IdUF:int}", Name = "MostraUF-Dados")] [ProducesResponseType(200)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status404NotFound)] public ActionResult<UF> MostraUF(int IdUF) { return BadRequest(); } /// <summary> /// Adiciona uma nova UF à lista /// </summary> /// <param name="NovaUF"></param> /// <returns></returns> [HttpPost(Name = "Adiciona-Dados")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult<IEnumerable<UF>> AdicionaUF(UF NovaUF) { return ListaUF(); } /// <summary> /// Altera todos os dados de uma UF baseado em um id /// </summary> /// <param name="IdUF">Id da UF que será alterada</param> /// <param name="NomeUF">Novo nome (sigla) da UF</param> /// <param name="CapitalUF">Novo nome da capital</param> /// <returns></returns> [HttpPut(Name = "Altera-Dados")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult<IEnumerable<UF>> AtualizaUF(int IdUF, string NomeUF, string CapitalUF) { return ListaUF(); } /// <summary> /// Muda apenas a capital de uma UF baseado no nome da UF /// </summary> /// <param name="NomeUF">Nome da UF (sigla)</param> /// <param name="NovaCapital">Nome da nova capital</param> /// <returns></returns> [HttpPatch(Name = "MudaCapital-Dados")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult<IEnumerable<UF>> MudaCapital(string NomeUF, string NovaCapital) { return ListaUF(); } /// <summary> /// Elimina uma UF baseado no id /// </summary> /// <param name="DelId">Id da UF que será eliminada</param> /// <returns></returns> [HttpDelete(Name = "EliminaUF-Dados")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status404NotFound)] public ActionResult<IEnumerable<UF>> EliminaUF(int DelId) { return ListaUF(); } } }
Vamos também incrementar a classe “UF.cs” para incluir as “Annotations”. Elas serão importantes depois para as operações envolvendo bancos de dados.
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; namespace Treino_REST_02.Models { [Table("Capitais")] public class UF { [Required] [Column("Id",TypeName = "int")] [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int Id { get; set; } [Required] [Column("UF", TypeName = "char")] [MaxLength(2)] public required string Nome { get; set; } [Required] [Column("Capital",TypeName = "varchar")] [MaxLength(50)] public string? Capital { get; set; } } }
Tendo feito essas operações, agora temos um esqueleto de operações CRUD que, até o momento ainda não faz nada, mas já responde no Swagger.
Ainda nessa parte de preparação do ambiente, vamos já definir a Connection String, pois o padrão MVC tem um lugar especial para ela no arquivo “appsettings.json”, conforme pode ser visto nas linhas 9, 10 e 11:
{ "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } }, "AllowedHosts": "*", "ConnectionStrings": { "cnMain": "Server=localhost;Database=Treino01;Trusted_Connection=True;MultipleActiveResultSets=true" } }
Para fazer a leitura da ConnectionString dentro do código do programa, vamos instanciar um objeto da classe IConfiguration da seguinte forma:
namespace Treino_REST_02.Controllers { [Route("api/Dados")] [ApiController] public class DadosController : ControllerBase { IConfiguration Config; public DadosController(IConfiguration _config) { this.Config = _config; }
Apesar de a referência para IConfiguration ser passada no construtor, observe que instanciei o objeto “Config” no nível da classe e não dentro do método construtor. Dessa forma, “Config” pode ser chamado por qualquer método do programa. Para ler a string de conexão agora basta utilizar o método “Config.GetConnectionString()” como no exemplo abaixo:
Cn.ConnectionString = Config.GetConnectionString("cnMain");
Outra forma de fazer a leitura da string de conexão sem precisar deixar um objeto instanciado é essa abaixo, porém tenho a impressão que este método demanda mais recursos computacionais. Ainda farei uma pesquisa sobre o assunto para chegar à uma conclusão final.
var cnStr = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build().GetSection("ConnectionStrings")["cnMain"];
O próximo passo vai ser implementar o acesso a dados tanto com ADO.NET quanto com Entity Framework.