Módulo 3 · Arquitetura MVC — Capítulo 02

Controllers, Actions e Routing

Como uma URL chega até um método C# específico — controllers, actions e as duas formas de definir rotas no ASP.NET Core.

1. Um Controller é uma classe; uma Action é um método

C# ClienteController.cs
public class ClienteController : Controller
{
    private readonly ClienteService _service;

    public ClienteController(ClienteService service) => _service = service;

    // Action — cada método público (não privado) é um endpoint em potencial
    public async Task<IActionResult> Listar()
    {
        var clientes = await _service.ListarAsync(null, true);
        return View(clientes);
    }

    public async Task<IActionResult> Detalhes(int id)
    {
        var cliente = await _service.ObterOuFalharAsync(id);
        return View(cliente);
    }
}

Toda classe cujo nome termina em Controller e herda de Controller é descoberta automaticamente pelo framework — sem precisar registrar rotas manualmente uma a uma, como você faria em app.get(...) do Express.

2. Routing baseado em convenção

Por padrão, o ASP.NET Core MVC usa um padrão de rota que mapeia /{controller}/{action}/{id?} diretamente para classe/método/parâmetro:

/Cliente/Detalhes/42 ClienteController Detalhes(...) int id = 42

Fig. 1 — Roteamento por convenção: cada segmento da URL mapeia direto para classe, método e parâmetro.

C# Program.cs — registrando a rota por convenção
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();

var app = builder.Build();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.Run();

3. Routing baseado em atributos — controle explícito

Para rotas mais específicas (comum em APIs, aprofundado no Módulo 4), atributos dão controle total sobre a URL, sem depender da convenção de nomes:

C# rotas com atributos
[Route("clientes")]
public class ClienteController : Controller
{
    [Route("")]                 // GET /clientes
    public async Task<IActionResult> Listar() { ... }

    [Route("{id:int}")]         // GET /clientes/42 (só aceita id numérico)
    public async Task<IActionResult> Detalhes(int id) { ... }

    [Route("ativos")]           // GET /clientes/ativos
    public async Task<IActionResult> Ativos() { ... }
}
Restrição de rotaExemploEfeito
:int{'{'}id:int{'}'}Só casa se o segmento for um número inteiro
:required{'{'}nome:required{'}'}Segmento obrigatório
?{'{'}id?{'}'}Segmento opcional

4. Verbos HTTP em uma Action

Por padrão, uma Action responde a qualquer verbo. Atributos de verbo restringem isso — essencial quando a mesma URL tem comportamentos diferentes para exibir um formulário (GET) e processá-lo (POST):

C# GET vs. POST na mesma URL
[HttpGet("clientes/novo")]
public IActionResult Novo() => View(); // exibe o formulário vazio

[HttpPost("clientes/novo")]
public async Task<IActionResult> Novo(Cliente cliente)
{
    if (!ModelState.IsValid)  // validação — capítulo 5
        return View(cliente);

    await _service.CriarAsync(cliente);
    return RedirectToAction(nameof(Listar));
}
Dica — Post/Redirect/Get

Repare no RedirectToAction após o POST bem-sucedido, em vez de devolver uma View diretamente. Esse padrão (Post/Redirect/Get) evita que o usuário reenvie o mesmo formulário sem querer ao apertar F5 — o navegador vai reexecutar o último GET, não o POST original.

5. IActionResult — os tipos de resposta mais comuns

RetornoResposta HTTP gerada
View(modelo)Renderiza a View correspondente com o modelo
RedirectToAction(nome)302, redireciona para outra action
NotFound()404
BadRequest(erros)400, com detalhes do erro
Json(dados)200 com corpo JSON (mais comum no Módulo 4, APIs)

6. Onde isso te leva

Com controllers, actions e rotas cobertos, o próximo capítulo completa o outro lado da resposta View(modelo): como o Razor transforma esse modelo em HTML de verdade.

📌 Resumo do capítulo

  • Um Controller é uma classe; cada método público é uma Action, um endpoint em potencial.
  • Routing por convenção ({'{'}controller{'}'}/{'{'}action{'}'}/{'{'}id?{'}'}) mapeia URL para código sem configuração manual; routing por atributos dá controle explícito.
  • [HttpGet]/[HttpPost] restringem uma Action a um verbo específico — essencial no padrão Post/Redirect/Get.
  • IActionResult é o tipo de retorno comum a View(), RedirectToAction(), NotFound() e outros.

✏️ Praticando

  1. Crie ClienteController com as actions Listar, Detalhes(int id) e Novo (GET e POST), usando routing por atributos.
  2. Adicione a restrição :int na rota de Detalhes e teste acessar com um valor não numérico — confirme que devolve 404.
  3. Implemente o padrão Post/Redirect/Get completo no formulário de criação de cliente.