ASP .NET Core - Transformando código síncrono para assíncrono - II


 Hoje vamos continuar mostrando como transformar código síncrono para assíncrono na plataforma .NET.

Continuando a primeira parte do artigo vamos iniciar a conversão do código usando async/await começando pela implementação do repositório.

Convertendo a implementação do Repositório

Como estamos usando o Entity Framework Core temos a disposição todos os métodos assíncronos para realizar a operação relacionada ao CRUD.

O EF Core fornece métodos como FindAsync(), SaveChangesAsync(), AddRangeAsync(), AddAsync(), etc., que oferecem uma maneira assíncrona de trabalhar com o contexto do  EF Core. Assim na conversão vamos usar esses métodos.

A primeira etapa deve ser redefinir o código da interface IProdutoRepository tornando-os assíncronos.

Para isso vamos usar a classe Task que representa uma operação assíncrona:

public interface IProdutoRepository
{
        Task<IEnumerable<Produto>> GetProdutosAsync();
        Task<Produto> GetProdutoAsync(int? id);
        Task<Produto> CreateAsync(Produto produto);
        Task<Produto> UpdateAsync(Produto produto);
        Task<Produto> RemoveAsync(Produto produto);
}

Usamos o sufixo Async no nome de cada contrato para evidenciar que eles devem ser implementados usando async/await.

A seguir vamos converter o código da classe ProdutoRepository incluindo as palavras-chave async/await e Task.

using API_Conversao.Context;
using API_Conversao.Models;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace API_Conversao.Repositories
{
    public class ProdutoRepository : IProdutoRepository
    {
        private ApplicationDbContext _produtoContext;
        public ProdutoRepository(ApplicationDbContext context)
        {
            _produtoContext = context;
        }

        public async Task<Produto> CreateAsync(Produto produto)
        {
            _produtoContext.Add(produto);
            await _produtoContext.SaveChangesAsync();
            return produto;
        }

        public async Task<Produto> GetProdutoAsync(int? id)
        {
            return await _produtoContext.Produtos.FindAsync(id);
        }

        public async Task<IEnumerable<Produto>> GetProdutosAsync()
        {
            return await _produtoContext.Produtos.ToListAsync();
        }

        public async Task<Produto> RemoveAsync(Produto produto)
        {
            _produtoContext.Remove(produto);
            await _produtoContext.SaveChangesAsync();
            return produto;
        }

        public async Task<Produto> UpdateAsync(Produto produto)
        {
            _produtoContext.Update(produto);
            await _produtoContext.SaveChangesAsync();
            return produto;
        }
    }
}

Assim observe que na assinatura de cada método incluímos as palavras chaves async Task ou async Task<T>.

Também usamos os seguintes métodos do EF Core:

Conversão do controlador ProdutosController

Agora precisamos converter o código usado na implementação do controlador para assíncrono.

using API_Conversao.Models;
using API_Conversao.Repositories;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace API_Conversao.Controllers
{
    [Route("api/[Controller]")]
    [ApiController]
    public class ProdutosController : Controller
    {
        private readonly IProdutoRepository _produtoRepository;

        public ProdutosController(IProdutoRepository produtoService)
        {
            _produtoRepository = produtoService;
        }

        // api/produtos
        [HttpGet]
        public async Task<ActionResult<IEnumerable<Produto>>> Get()
        {
            var produtos = await _produtoRepository.GetProdutosAsync();
            return Ok(produtos);
        }

        [HttpGet("{id}", Name = "GetProduto")]
        public async Task<ActionResult<Produto>> Get(int id)
        {
            var produto = await _produtoRepository.GetProdutoAsync(id);

            if (produto == null)
            {
                return NotFound();
            }
            return Ok(produto);
        }

        [HttpPost]
        public async Task<ActionResult> Post([FromBody] Produto produto)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            await _produtoRepository.CreateAsync(produto);

            return new CreatedAtRouteResult("GetProduto",
                new { id = produto.Id }, produto);
        }

        [HttpPut("{id}")]
        public async Task<ActionResult> Put(int id, [FromBody] Produto produto)
        {
            if (id != produto.Id)
            {
                return BadRequest();
            }

            await _produtoRepository.UpdateAsync(produto);

            return Ok(produto);
        }

        [HttpDelete("{id}")]
        public async Task<ActionResult<Produto>> Delete(int id)
        {
            var produto = await _produtoRepository.GetProdutoAsync(id);
            if (produto == null)
            {
                return NotFound();
            }
            await _produtoRepository.RemoveAsync(produto);
            return Ok(produto);
        }
    }
}

Com isso agora temos a implementação do repositório e do controlador usando a programação assíncrona com async/await e Task.

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

"Disse-lhe Jesus: Porque me viste, Tomé, creste; bem-aventurados os que não viram e creram."
João 20:29

Referências:


José Carlos Macoratti