Mais 4 Recomendações Práticas para Projetos de Microsserviços em .NET

Neste post, compartilho mais algumas ideias que tenho adotado, com êxito, em meus projetos envolvendo Microsserviços e que podem ajudar você a ser mais efetivo em suas implementações.

Se você ainda não leu, recomendo que acesse um post anterior sobre esse tema, com mais recomendações, antes de avançar.

1. Comece pelos comandos e pelas consultas que vai suportar

Antes de definir qualquer aspecto mais técnico, ter clareza sobre quais comandos e consultas seu microsserviço deverá suportar irá ajudar você a ser mais efetivo e mais alinhado com as necessidades do negócio.


No exemplo, apenas ilustrativo, o microsserviço irá manter um “contador”.

Tenho optado (não faz muito tempo) por usar o Mediatr para intermediar a chamada dos handlers, orquestrar validação das mensagegens, etc.

using System.Threading;
using System.Threading.Tasks;
using CountingMicroservice.Application.Services;
using MediatR;

namespace CountingMicroservice.Application.CommandSide.Commands
{
    public class IncrementCommandHandler
        : IRequestHandler<IncrementCommand, bool>
    {
        private readonly ICounterRepository _repository;

        public IncrementCommandHandler(ICounterRepository repository)
        {
            _repository = repository;
        }

        public Task Handle(
            IncrementCommand request, 
            CancellationToken cancellationToken
            )
        {
            if (request == null)
            {
                return Task.FromResult(false);
            }

            _repository.Increment();
                
            return Task.FromResult(true);
        }
    }
}

2. Mantenha sua WebApi simples (se essa for sua interface)

Manter um projeto específico para a aplicação permite que o projeto da Web API seja extremamente simplificado. Caberá a WebAPI, apenas, fazer as devidas inicializações e prover features que “chamam” os comandos e consultas no momento apropriado.

Aliás, para aliviar acoplamento, tenho adotado por hábito fazer inicializações específicas da aplicação no código da aplicação (fora da web api)

using CountingMicroservice.Application.Services;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using ServiceStack.Redis;

namespace CountingMicroservice.Application
{
    public static class StartupExtensions
    {
        public static IServiceCollection AddCounterApplication(
            this IServiceCollection services, 
            IConfiguration configuration
            )
        {
            var redisConnectionString = configuration["REDIS_CONNECTIONSTRING"] ?? "-counter.data";
            services
                .AddSingleton(sp => 
                    new RedisManagerPool(redisConnectionString)
                    )
                .AddSingleton<ICounterRepository, RedisCounterRepository>();

            return services;
        }

        public static IApplicationBuilder UseCounterApplication(
            this IApplicationBuilder app
        )
        {
            return app;
        }
    }
}

Fica dentro da WebAPI apenas inicializações que são específicas dela (Swagger, por exemplo)

using System;
using Autofac;
using Autofac.Extensions.DependencyInjection;
using CountingMicroservice.Application;
using CountingMicroservice.Application.CommandSide.Commands;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Swashbuckle.AspNetCore.Swagger;

namespace CountingMicroservice.WebApi
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        public IServiceProvider ConfigureServices(IServiceCollection services)
        {
            services.AddMvc(options =>
            {
                options.RespectBrowserAcceptHeader = true;
            });

            services.AddSwaggerGen(options =>
            {
                options.SwaggerDoc("v1", new Info()
                {
                    Title = "Counting Microservice",
                    Version = "v1",
                    Description = "Basic Microservice Example"
                });
            });

            services.AddCounterApplication(Configuration);

            var container = new ContainerBuilder();
            container.RegisterModule(
                MediatrModule.Create(typeof(StartupExtensions).Assembly)
                );
            container.Populate(services);
            return new AutofacServiceProvider(container.Build());
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseMvcWithDefaultRoute();

            app
                .UseSwagger()
                .UseSwaggerUI(options =>
                {
                    options.SwaggerEndpoint(
                        "/swagger/v1/swagger.json",
                        "Counting Microservice v1"
                        );
                });

            app.UseCounterApplication();
        }
    }
}

3. Use e abuse do Docker

Provavelmente seu microsserviço irá rodar em um container;. Aproveite-se do suporte do Visual Studio para Docker e já comece seu projeto rodando e depurando em containers.

O efeito positivo dessa escolha é que ficará muito mais fácil gerenciar dependências de softwares tecerceiros. Veja o docker-compose.yml da aplicação exemplo

version: '3'

services:
  countingmicroservice.webapi:
    image: countingmicroservice.webapi
    build:
      context: .
      dockerfile: CountingMicroservice.WebApi/Dockerfile
    depends_on:
      - redis

  redis:
    image: redis

No exemplo, não preciso mais me preocupar em ter um servidor redis rodando em meu Windows. Ao começar a rodar minha aplicação, uma imagem do Redis irá ser baixada e um container iniciado.

4. Use variáveis de ambiente para configuração

É muito mais fácil configurar sua aplicação usando variáveis de ambiente do que utilizando arquivos de configuração. No Asp.net Core, é simples fazer isso.

namespace CountingMicroservice.WebApi
{
    public class Program
    {
        public static void Main(string[] args)
        {
            BuildWebHost(args).Run();
        }

        public static IWebHost BuildWebHost(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup()
                .ConfigureAppConfiguration((builderContext, config) =>
                {
                    config.AddEnvironmentVariables();
                })
                .Build();
    }
}

Além disso, variáveis de ambiente são perfeitas combinadas ao Docker. No exemplo, configuro endereço do Redis no arquivo de composição. Isso simplificará muito o deploy mais tarde.

version: '3'

services:
  countingmicroservice.webapi:
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
      - REDIS_CONNECTIONSTRING=redis
    ports:
      - "5000:80"

  redis:
    ports:
      - "6379:6379"

Concluindo

Novamente, “são as cicatrizes que contam a história do guerreiro”.

  • Sempre achei tedioso fazer o link entre meus Controllers e o código do domínio. Mediatr é uma “mão na roda” e a separação do microsserviço em projetos “adaptadores” e um “core” me ajuda a manter focado no negócio.
  • A ideia de implementar comandos e consultas me faz manter o foco nas histórias de negócio ao invés de dados colecionados.
  • Sempre achei péssimo instalar bancos de dados e outros artefatos em meu computador apenas para desenvolver – Docker é vida!
  • Sempre odiei o web.config! Felizmente, não preciso mais dele. Adoro a ideia de poder usar simples variáveis de ambiente para configurar minha aplicação.

Novamente, há bem mais que poderia ser compartilhado. Entretanto, mais uma vez, é hora de pedir a sua opinião.

 

Compartilhe este insight:

Elemar Júnior

Sou fundador e CEO da EximiaCo e atuo como tech trusted advisor ajudando diversas empresas a gerar mais resultados através da tecnologia.

Elemar Júnior

Sou fundador e CEO da EximiaCo e atuo como tech trusted advisor ajudando diversas empresas a gerar mais resultados através da tecnologia.

Mais insights para o seu negócio

Veja mais alguns estudos e reflexões que podem gerar alguns insights para o seu negócio:

Em minhas consultorias, quando questionado sobre escalabilidade, recorro sempre ao scale cube, compartilhado no excelente livro “The Art of Scalability”,...
Ontem, dia 25/07/2018, a convite do Canal.NET, compartilhei alguns insights sobre modelagem de microsserviços a partir de processos de negócio....
Você ainda acredita em estimativas? Nós, não. Embora aceitemos que ter uma boa ideia de esforço e prazo sejam diferenciais...
Superficialmente, direito e privilégio são conceitos que se aproximam e, eventualmente, se confundem. Mas, com um pouco de cuidado, ficam...
Este é o primeiro post de uma série onde pretendo compartilhar, com considerável nível de detalhe, como resolver problemas de...
Anualmente, como Microsoft MVP & RD, participo de uma conferência global, organizada pela Microsoft, na sede da empresa em Redmond....

Inscrição realizada com sucesso!

No dia da masterclass você receberá um e-mail com um link para acompanhar a aula ao vivo. Até lá!

A sua subscrição foi enviada com sucesso!

Aguarde, em breve entraremos em contato com você para lhe fornecer mais informações sobre como participar da mentoria.

Crie sua conta

Preencha os dados para iniciar o seu cadastro no plano anual do Clube de Estudos:

Crie sua conta

Preencha os dados para iniciar o seu cadastro no plano mensal do Clube de Estudos:

× Precisa de ajuda?