O objetivo deste artigo é demonstrar o uso do SQL Server e do Micro-ORM Dapper na implementação de uma API REST com o ASP.NET Core 1.0.

Introdução

É inegável que mecanismos de mapeamento objeto-relacional (ORM) simplificam em muito o desenvolvimento de aplicações que dependam de bancos de dados convencionais. Considerando especificamente a plataforma .NET, o Entity Framework e o NHibernate são hoje as opções mais populares neste segmento.

Apesar de toda a praticidade e agilidade oferecidas, há cenários em que estas alternativas não constituem a melhor resposta. Isto se evidencia em situações nas quais a performance é um fator crítico. As instruções SQL geradas automaticamente por um framework ORM podem apresentar um desempenho abaixo do esperado, com os desenvolvedores não contando com meios viáveis para otimizar/customizar tais comandos.

Um caminho então seria o desenvolvimento baseado em recursos do ADO.NET, mas tal abordagem esbarra em problemas de produtividade na codificação. Como então superar estas dificuldades? Frameworks conhecidos como Micro-ORMs podem ser uma boa resposta a tal questionamento.

Com ênfase na escrita de poucas linhas de código e velocidade no acesso a dados o Dapper é atualmente um dos Micro-ORMs mais populares em .NET. Suas diversas funcionalidades foram disponibilizadas como Extension Methods, acessíveis a partir de implementações da interface IDbConnection. Vale lembrar que IDbConnection é o tipo básico para acesso a dados do ADO.NET e do qual derivam classes como SqlConnection e OracleConnection.

Neste artigo será demonstrado um exemplo básico de uso do Dapper em aplicações criadas com o ASP.NET Core 1.0, com isto acontecendo através da implementação de uma API REST para consulta a cotações de moedas estrangeiras.

Exemplo de utilização

Para implementar o projeto apresentado neste artigo foram utilizados como recursos:
  • O Microsoft Visual Studio Community 2015 Update 3 como IDE de desenvolvimento;
  • O .NET Core 1.0;
  • O ASP.NET Core 1.0;
  • Uma base de dados do SQL Server;
  • O Dapper como solução de acesso a dados.
Como primeiro passo será necessário proceder com a criação de um banco de dados chamado Cotacoes no SQL Server. Essa base contará com uma tabela também chamada Cotacoes, sendo que a estrutura e os dados esperados para a mesma estão no seguinte script:

USE Cotacoes
GO
 
CREATE TABLE dbo.Cotacoes(
    Sigla char(3) NOT NULL,
    NomeMoeda varchar(30) NOT NULL,
    UltimaCotacao datetime NOT NULL,
    Valor numeric (18,4) NOT NULL,
    CONSTRAINT PK_Cotacoes PRIMARY KEY (Sigla)
)
GO
 
 
INSERT INTO dbo.Cotacoes
           (Sigla
           ,NomeMoeda
           ,UltimaCotacao
           ,Valor)
     VALUES
           ('USD'
           ,'Dólar norte-americano'
           ,'2016-11-04 17:00'
           ,3.2311)
 
INSERT INTO dbo.Cotacoes
           (Sigla
           ,NomeMoeda
           ,UltimaCotacao
           ,Valor)
     VALUES
           ('EUR'
           ,'Euro'
           ,'2016-11-04 17:00'
           ,3.6066)
 
INSERT INTO dbo.Cotacoes
           (Sigla
           ,NomeMoeda
           ,UltimaCotacao
           ,Valor)
     VALUES
           ('LIB'
           ,'Libra esterlina'
           ,'2016-11-04 17:00'
           ,4.0493)

Criar logo após isto um projeto do tipo ASP.NET Core Web Application (.NET Core) chamado TesteAPIRESTDapper:



Selecionar na sequência a opção Web API em ASP.NET Core Templates:



Em seguida será preciso adicionar ainda os packages System.Data.SqlClient e Dapper via NuGet, como indicado na próxima imagem:



A classe Cotacao conterá a sigla que identifica uma moeda estrangeira, o nome da mesma, a data da última cotação e seu valor correspondente:

using System;
 
namespace TesteAPIRESTDapper
{
    public class Cotacao
    {
        public string Sigla { get; set; }
        public string NomeMoeda { get; set; }
        public DateTime UltimaCotacao { get; set; }
        public decimal Valor { get; set; }
    }
}

Já o tipo CotacoesDAO será empregado na manipulação dos dados dos quais a aplicação de testes depende:
  • O construtor de CotacoesDAO receberá uma instância que implementa a interface IConfiguration (namespace Microsoft.Extensions.Configuration), utilizada neste caso para acessar a string de conexão (BaseCotacoes) que aponta para a base Cotacoes. Importante destacar que esta referência será resolvida via mecanismo nativo de injeção de dependências do ASP.NET Core;
  • O método Obter receberá como parâmetro a sigla que identifica uma moeda, devolvendo como resultado uma instância do tipo Cotacao com as informações mais recentes sobre a mesma. Para isto será criada uma instância do tipo SqlConnection (namespace System.Data.SqlClient) e, a partir deste objeto, acessado o Extension Method QueryFirst que integra o Dapper;
  • Serão informados à operação QueryFirst uma expressão SQL para a seleção de dados da tabela Cotacoes, além de um tipo anônimo que mapeará o parâmetro @SiglaMoeda para o valor armazenado pelo parâmetro idMoeda.
using System.Data.SqlClient;
using Microsoft.Extensions.Configuration;
using Dapper;
 
namespace TesteAPIRESTDapper.Data
{
    public class CotacoesDAO
    {
        private IConfiguration _configuracoes;
        public CotacoesDAO(IConfiguration config)
        {
            _configuracoes = config;
        }
 
        public Cotacao Obter(string idMoeda)
        {
            using (SqlConnection conexao = new SqlConnection(
                _configuracoes.GetConnectionString("BaseCotacoes")))
            {
                return conexao.QueryFirstOrDefault<Cotacao>(
                    "SELECT " +
                        "Sigla, " +
                        "NomeMoeda, " +
                        "UltimaCotacao, " +
                        "Valor " +
                    "FROM dbo.Cotacoes " +
                    "WHERE Sigla = @SiglaMoeda ",
                    new { SiglaMoeda = idMoeda });
            }
        }
    }
}

O arquivo appSettings.json armazenará a string de conexão BaseCotacoes para acesso à base de testes:

{
  "ConnectionStrings": {
    "BaseCotacoes": "Data Source =.\\SQLEXPRESS; Initial Catalog = Cotacoes; Integrated Security = SSPI;"
  },
  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Debug",
      "System": "Information",
      "Microsoft": "Information"
    }
  }
}

A classe Startup também passará por alterações:
  • A propriedade Configuration armazenará uma instância de uma classe que deriva de IConfigurationRoot (namespace Microsoft.Extensions.Configuration), um subtipo de IConfiguration;
  • A operação ConfigureSevices receberá como parâmetro uma referência do tipo IServiceCollection (namespace Microsoft.Extensions.DependencyInjection), a qual será utilizada na especificação das diferentes dependências do projeto;
  • O uso do método AddSingleton faz com que uma única referência de IConfiguration seja utilizada na resolução de todas as dependências encontradas ao longo da aplicação, sendo este um exemplo prático de aplicação do pattern Singleton;
  • Já para o tipo CotacoesDAO será acionado o método AddTransient. Esta instrução fará com que uma nova instância de CotacoesDAO seja gerada sempre que se encontrar uma dependência baseada nesta classe.
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using TesteAPIRESTDapper.Data;
 
namespace TesteAPIRESTDapper
{
    public class Startup
    {
        ...
 
        public IConfigurationRoot Configuration { get; }
 
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddSingleton<IConfiguration>(
                _ => Configuration);
            services.AddTransient<CotacoesDAO>();
 
            ...
        }
 
        ...
    }
}

Por fim, a próxima listagem traz a implementação da classe CotacoesController. Este Controller será utilizado no processamento de requisições HTTP envolvendo a consulta a cotações de moedas estrangeiras:
  • A classe CotacoesController foi marcada com o atributo Route, de forma que chamadas à API utilizem como caminho-base o valor /api/cotacoes;
  • Já no atributo HttpGet o valor {id} indica que a sigla de uma moeda estrangeira fará parte das URLs a serem processadas pelo método Get;
  • O primeiro parâmetro da operação Get foi marcado com o atributo FromServices, de maneira que a dependência representada por CotacoesDAO seja resolvida automaticamente pelo ASP.NET Core ao se acionar este método;
  • Uma chamada ao método Obter de CotacoesDAO retornará então as informações mais atuais sobre uma moeda.
using Microsoft.AspNetCore.Mvc;
using TesteAPIRESTDapper.Data;
 
namespace TesteAPIRESTDapper.Controllers
{
    [Route("api/[controller]")]
    public class CotacoesController : Controller
    {
        [HttpGet("{id}")]
        public Cotacao Get(
            [FromServices]CotacoesDAO cotacoesDAO,
            string id)
        {
            return cotacoesDAO.Obter(id);
        }
    }
}

Testes

Um primeiro teste de consulta à cotação do dólar norte-americano via browser apresentará o seguinte resultado:



Na próxima imagem está o resultado da consulta à cotação do euro:



E a seguir a cotação da libra esterlina:

Conclusão

Desfrutando de grande popularidade entre desenvolvedores .NET, o Dapper é um Micro-ORM que apresenta uma performance superior quando comparado a frameworks tradicionais como Entity Framework e NHibernate. Os diferentes Extension Methods disponibilizados por esta solução funcionam em conjunto com implementações do tipo IDbConnection, evitando assim muito do trabalho que aconteceria ao se depender exclusivamente de recursos do ADO.NET.

Referências

ASP.NET Core 1.0 - Documentation
http://docs.asp.net/en/latest/

Dapper .NET
https://github.com/StackExchange/dapper-dot-net