ASP .NET Core - Implementando a Onion Architecture - VI


Neste artigo vamos criar uma aplicação ASP .NET Core WEBAPI fazendo uma implementação básica da arquitetura em Cebola ou Onion Architecture.

Continuando a quinta parte do artigo vamos iniciar a implementação do projeto eStore.API da camada de apresentação que representa a nossa Web API.

Implementação do projeto eStore.API

No projeto eStore.API vamos iniciar configurando os serviços do mapeamento feito com AutoMapper no projeto eStore.Application.

Assim vamos precisar incluir no projeto API uma instância do pacote :

install-package AutoMapper.Extensions.Microsoft.DependencyInjection -version 8.1.1

Após isso vamos criar uma pasta AutoMapConfig e nesta pasta criar a classe AutoMapperConfig e nesta classe o método de extensão chamado AddAutoMapperConfiguration que vai atuar no tipo IServiceCollection e registrar o serviço do AutoMapper para o mapeamento que já definimos.

1- AutoMapperConfig

using eStore.Application.Mappings;
using Microsoft.Extensions.DependencyInjection;
using System;

namespace eStore.API.AutoMapConfig
{
    public static class AutoMapperConfig
    {
        public static void AddAutoMapperConfiguration(this IServiceCollection services)
        {
            if (services == null) throw new ArgumentNullException(nameof(services));
                 services.AddAutoMapper(typeof(DomainToDTOMappingProfile));
        }
    }
}

A seguir precisamos definir na classe Startup a utilização dos serviços dos repositórios e demais serviços criados na camada Application.

Para isso no método ConfigureServices da classe Startup inclua o código abaixo onde usamos os métodos de extensão AddInfrastrucure e AddAutoMapperConfiguration criados:

  public void ConfigureServices(IServiceCollection services)
  {
            services.AddInfrastructure(Configuration);
            services.AddAutoMapperConfiguration();

            services.AddControllers();
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo { Title = "eStore.API", Version = "v1" });
            });
   }

Agora podemos criar os controladores na pasta Controllers. E vamos criar dois controladores:

Esses controladores representam as APIs do nosso projeto.

Criando a API CategoryController

Vamos iniciar com CategoryController:

using eStore.Application.DTOs;
using eStore.Application.Interfaces;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace eStore.API.Controllers
{
    [Route("api/[controller]")]
    [ApiController]

    public class CategoryController : ControllerBase
    {
        private readonly ICategoryService _categoryService;
        public CategoryController(ICategoryService categoryAppService)
        {
            _categoryService = categoryAppService;
        }

        [HttpGet]
        public async Task<ActionResult<IEnumerable<CategoryDTO>>> Get()
        {
            var categories = await _categoryService.GetCategories();
            if (categories == null)
            {
                return NotFound();
            }
            return Ok(categories);
        }

        [HttpGet("{id}", Name = "GetCategory")]
        public async Task<ActionResult<CategoryDTO>> Get(int id)
        {
            var produto = await _categoryService.GetById(id);
            if (produto == null)
            {
                return NotFound();
            }
            return Ok(produto);
        }
        [HttpPost]
        public async Task<ActionResult> Post([FromBody] CategoryDTO categoryDto)
        {
            await _categoryService.Add(categoryDto);

            return new CreatedAtRouteResult("GetCategory",
                new { id = categoryDto.Id }, categoryDto);
        }

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

            await _categoryService.Update(categoryDto);

            return Ok(categoryDto);
        }

        [HttpDelete("{id}")]
        public async Task<ActionResult<CategoryDTO>> Delete(int id)
        {
            var categoryDto = await _categoryService.GetById(id);
            if (categoryDto == null)
            {
                return NotFound();
            }
            await _categoryService.Remove(categoryDto);
            return Ok(categoryDto);
        }
    }
}

Temos neste código a implementação dos métodos :

Podemos testar cada método usando a interface do Swagger que já foi implementado por padrão quando criamos o projeto.

Testando a API - CategoryController

Vamos agora testar cada um dos métodos implementados usando a interface do Swagger.

Para isso vamos executar o projeto e com isso iremos obter na interface Swagger os endpoints definidos para cada API :

A seguir temos os testes feitos:

Temos assim todos os endpoints testados e funcionando.

Criando e Testando a API - ProductController

A seguir temos o código da API ProductController:

using eStore.Application.DTOs;
using eStore.Application.Interfaces;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace eStore.API.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class ProductController : ControllerBase
    {
        private readonly IProductService _productService;
        public ProductController(IProductService productAppService)
        {
            _productService = productAppService;
        }

        [HttpGet]
        public async Task<ActionResult<IEnumerable<ProductDTO>>> Get()
        {
            var produtos = await _productService.GetProducts();
            if (produtos == null)
            {
                return NotFound();
            }
            return Ok(produtos);
        }

        [HttpGet("{id}", Name = "GetProduct")]
        public async Task<ActionResult<ProductDTO>> Get(int id)
        {
            var produto = await _productService.GetById(id);
            if (produto == null)
            {
                return NotFound();
            }
            return Ok(produto);
        }
        [HttpPost]
        public async Task<ActionResult> Post([FromBody] ProductDTO produtoDto)
        {
            await _productService.Add(produtoDto);

            return new CreatedAtRouteResult("GetProduct",
                new { id = produtoDto.Id }, produtoDto);
        }

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

            await _productService.Update(produtoDto);

            return Ok(produtoDto);
        }

   
        [HttpDelete("{id}")]
        public async Task<ActionResult<ProductDTO>> Delete(int id)
        {
            var produtoDto = await _productService.GetById(id);
            if (produtoDto == null)
            {
                return NotFound();
            }
            await _productService.Remove(produtoDto);
            return Ok(produtoDto);
        }
    }  
}

Temos neste código a implementação dos métodos :

Podemos testar cada método usando a interface do Swagger que já foi implementado por padrão quando criamos o projeto.

Concluímos assim a implementação do nosso projeto segundo as diretrizes da Onion Architecture.

Poderíamos continuar implementando outras funcionalidades e fazendo alguns ajustes mas o objeto principal foi cumprido.

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

"Bem-aventurados os pobres de espírito, porque deles é o reino dos céus; Bem-aventurados os que choram, porque eles serão consolados; "
Mateus 5:3,4

Referências:


José Carlos Macoratti