Neste post, gostaria de compartilhar a estrutura que venho adotando em meus projetos com microsserviços. São algumas ideias que tenho adotado com êxito e que podem ajudar você a ter mais sucesso em seus próprios projetos.
Se tiver interesse em entender mais sobre microsserviços, recomendo que acesse o Guia de Conteúdo para Microsserviços deste site.
1. Adote arquitetura hexagonal
Gosto muito do conceito de arqutitetura hexagonal (leia o post relacionado se não está familiarizado com o cenceito) e, para microsserviços, entendo que o conceito se ajusta perfeitamente.
Seguindo essa ideia, sempre que começo a criar um microsserviço em .NET, crio dois projetos. Um que irá operar conter a aplicação (entenda-se: código do domínio) e outro que irá expor essa aplicação para meios externos (geralmente um cliente de mensageria ou uma web api)

2. Organize seu código em Feature folders
Nunca me senti confortável com a separação de código em pastas técnicas (entenda-se Controllers, Views e Models). No lugar disso, prefiro organizar meu código por Features.

A idéia é manter Controller, Views, InputModels e ViewModels todos em uma única pasta agrupados pela feature que está sendo implementada.
Asp.Net Core é suficientemente inteligente para conseguir entender o que está ocorrendo com os Controllers e com as Models automaticamente. O único ajuste necessário é para explicitar onde estão as Views. De qualquer forma, algo simples:
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc.Razor;
namespace Web.Features
{
public class FeaturesLocationExpander : IViewLocationExpander
{
public void PopulateValues(ViewLocationExpanderContext context)
{
// nothing
}
public IEnumerable ExpandViewLocations(
ViewLocationExpanderContext context,
IEnumerable viewLocations)
{
return new[]
{
"/Features/{1}/{0}.cshtml", // feature specific content
"/Features/Shared/{0}.cshtml" // shared
};
}
}
}
Este código instrui o ASP.net core sobre onde localizar as Views. Para ativar esse código, basta modificar a configuração do Razor.
public void ConfigureServices(IServiceCollection services)
{
services.AddIdentityApplication(_configuration);
//
services.AddMvc();
services.Configure<RazorViewEngineOptions>(options =>
{
options.ViewLocationExpanders.Add(new FeaturesLocationExpander());
});
}
3. Identifique claramente as interfaces da aplicação (CommandSide e QuerySide)
Sou adepto a ideia de separar claramente interfaces de comando (que mudam o estado da aplicação) e consulta (que apenas recuperam informações) – entenda-se CQRS.

Essa segregação explícita ajuda a explicar melhor o conceito e tornar tudo mais evidente para quem vai interpretar o código.
4. Adote Swagger
Documentar a API é fundamental. Por isso, defendo a ideia de já começar o projeto usando Swagger. Por convenção, todos os meus microsserviços (apenas API), em seu endereço raiz, redirecionam para a interface Swagger.
using Microsoft.AspNetCore.Mvc;
namespace WebApi.Features.Home
{
public class HomeController : Controller
{
public IActionResult Index() =>
new RedirectResult("~/swagger");
}
}
Além disso, utilizo os pacotes Swashbuckle.AspNetCore e Swashbuckle.AspNetCore.Examples para fornecer uma experiência mais rica, fornecendo, inclusive, exemplos para dados que precisam ser enviados para o servidor.
[Authorize]
[Route("addpf")]
[HttpPut]
[ProducesResponseType((int)HttpStatusCode.BadRequest)]
[ProducesResponseType(typeof(ClientePF), (int)HttpStatusCode.OK)]
[SwaggerRequestExample(typeof(IncluirClientePFCommand), typeof(IncluirClientePFCommandExample))]
public async Task<IActionResult> AddPF(
[FromBody] IncluirClientePFCommand data,
[FromHeader(Name = "x-requestid")] string requestId
)
{
if (!ModelState.IsValid)
{
return ModelState.GenerateBadRequestFromExceptions();
}
Guid.TryParse(requestId, out var guid);
var commandResult = await _mediator.Send(new IdentifiedCommand<IncluirClientePFCommand, ClientePF>(
data,
guid
));
return commandResult != null
? (IActionResult)Ok(commandResult)
: BadRequest();
}
Aliás, todos meus projetos de API contem uma pasta dedicada para códigos de exemplo para Swagger.

Concluindo
Sempre afirmo que “São as Cicatrizes que contam a história do guerreiro”. Essas recomendações são oriundas de algumas cicatrizes. Há muitas outras que poderia compartilhar, mas, por agora, gostaria de saber sua opinião. Quais dessas práticas você já adota?

