Se você vem do Node.js, Python ou PHP, o nome “.NET” pode parecer algo pesado e corporativo. Mas a real é que o ASP.NET Core se tornou um dos frameworks mais versáteis do mercado. Ele é open-source, roda em qualquer lugar (Windows, Linux, Mac) e oferece uma performance que bate de frente com as linguagens mais rápidas da atualidade.

Vamos abrir o capô do ASP.NET e entender como ele organiza as coisas, sem preconceitos entre estilos de código.

O Coração do Sistema: O C# e o SDK

Antes de falar de web, entenda que o C# é a linguagem e o .NET SDK é o kit de ferramentas que compila e roda tudo. A grande vantagem aqui é a tipagem forte: o compilador é seu primeiro “revisor de código”, evitando que você tente acessar uma propriedade que não existe ou passe um texto onde deveria ser um número.

As Duas Portas de Entrada: Minimal APIs e Controllers

No ASP.NET moderno, você tem dois caminhos principais para criar seus endpoints. Ambos são profissionais, estáveis e suportados pela Microsoft.

1. Minimal APIs

Introduzidas nas versões mais recentes, elas permitem que você crie rotas com pouquíssimas linhas. É ideal para microsserviços ou para quem gosta de ver tudo em um lugar só, sem muita hierarquia de pastas.

C#
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

// Uma rota direta e simples
app.MapGet("/v1/hello", () => new { message = "Hello world, .NET!" });

app.Run();

2. Controllers

É o padrão clássico do MVC. Se o seu projeto vai ter dezenas de rotas e regras de negócio complexas, os Controllers ajudam a separar as responsabilidades por arquivos. Cada classe cuida de um “assunto” do sistema.

C#
[ApiController]
[Route("v1/...")]
public class UserController : ControllerBase
{
    [HttpGet]
    public IActionResult List() 
    {
        return Ok(new[] { "Hello", "World" });
    }
}

Como o fluxo funciona: O Pipeline de Middleware

Quando o cliente faz um pedido (HTTP), ele não cai direto no seu código. Ele passa por uma série de “estações” chamadas Middlewares.

  1. A Requisição chega: O servidor web (Kestrel) recebe o pacote.
  2. Middlewares de Ida: O código passa por validações de segurança, logs e autenticação. Se algo estiver errado (ex: usuário não logado), para ali mesmo e devolve um erro.
  3. O seu Código (Endpoint): Se tudo estiver ok, a requisição chega no seu método (seja Minimal API ou Controller). Você processa, busca no banco e gera a resposta.
  4. Middlewares de Volta: A resposta faz o caminho inverso, podendo ser compactada ou modificada antes de sair para o cliente.

Injeção de Dependência: O “Garçom” do Sistema

Um dos pontos mais fortes do ASP.NET, que assusta iniciantes mas salva vidas, é a Injeção de Dependência (DI).

Em vez de você dar um new BancoDeDados() dentro de cada função, você avisa ao ASP.NET no início do projeto: “Olha, sempre que alguém precisar de banco de dados, entregue esta configuração aqui”. O framework gerencia a criação e a destruição desses objetos para você. Isso deixa o código absurdamente mais fácil de testar e manter.

Na Prática (Model, Service e Controller)

Para o sistema não virar uma bagunça, o ASP.NET sugere uma divisão de tarefas. Imagine que você está criando um sistema de usuários. Em vez de colocar tudo no mesmo arquivo, dividimos assim:

  1. Model: É o formato dos dados (a planta baixa).
  2. Service: É onde o “cérebro” do sistema fica (a regra de negócio).
  3. Controller: É o porteiro que recebe a requisição e entrega para o Service.

Veja como esse trio trabalha junto:

1. O Model

C#
// Simples e direto: o que um usuário tem?
public record User(int Id, string Name, string Email);

2. O Service

Aqui é onde você faria um cálculo, validaria um dado ou salvaria no banco. Usamos uma Interface para que o sistema seja fácil de testar depois.

C#
public interface IUserService {
    List<User> ListAll();
}

public class UserService : IUserService {
    public List<User> ListarTodos() {
        // Finja que isso veio do banco de dados
        return new List<User> {
            new User(1, "Você Dev", "contato@dev.com"),
            new User(2, "Dev Leigo", "aprendiz@dotnet.com")
        };
    }
}

3. O Controller (A conexão com o mundo)

O Controller não sabe como os usuários são listados, ele apenas pede ao Service e entrega o resultado.

C#
[ApiController]
[Route("v1/users")]
public class UserController : ControllerBase {
    private readonly IUserService _service;

    // O ASP.NET entrega o Service pronto aqui via Injeção de Dependência
    public UserController(IUserService service) {
        _service = service;
    }

    [HttpGet]
    public IActionResult Get() {
        var list = _service.ListAll();
        return Ok(list); // Retorna 200 OK com o JSON automático
    }
}

O Fluxo: Quem manda em quem?

Para você não se perder, montei essa tabela rápida de responsabilidades. É o que eu sigo para manter o Clean Code em dia:

PeçaO que ela faz?O que ela NÃO deve fazer?
ControllerValida se a rota existe e responde ao cliente.Nunca deve ter lógica de banco ou cálculos.
ServiceFaz cálculos, valida regras e chama o banco.Não sabe se a requisição veio da Web ou de um robô.
ModelDefine como os dados aparecem.Não deve ter lógica nenhuma, apenas propriedades.

No fim das contas…

O ASP.NET Core não tenta te prender a uma única forma de trabalhar. Quer algo rápido e direto? Vá de Minimal APIs. Precisa de uma estrutura robusta para um time grande? Use Controllers com Services.

O importante é entender que, por trás da sintaxe, existe um sistema de pipeline e injeção de dependência que garante que sua aplicação seja escalável desde o primeiro dia. Se você já tem uma base de lógica de programação, o próximo passo é baixar o SDK e rodar o seu primeiro dotnet watch para ver a mágica acontecer em tempo real.