ASP.NET Core - Vinculação de parâmetros


 Neste artigo veremos com é feita a vinculação de parâmetros a partir do .NET 7.0.

Hoje veremos como usar a vinculação de parâmetros no ASP.NET Core para converter dados de uma solicitação em parâmetros fortemente tipados, melhorando o desempenho do aplicativo e a capacidade de manutenção do código.

O que é vinculação de parâmetros?

A vinculação de parâmetros envolve o mapeamento de dados de solicitação HTTP recebidos para parâmetros de métodos Action no controlador, permitindo que os desenvolvedores processem solicitações e respondam de maneira estruturada e eficiente.

A vinculação de parâmetros simplifica o processo de manipulação de solicitações HTTP e permite que se concentrar na construção da lógica de seus endpoints de API. A ASP.NET Core oferece vários tipos de vinculação de parâmetros, incluindo FromQuery, FromRoute, FromHeader e FromBody.

A vinculação de parâmetros na ASP.NET Core funciona assim:

Quando um cliente faz uma solicitação HTTP para uma API, os dados da solicitação são automaticamente mapeados para parâmetros do método de ação com base nos nomes e tipos dos parâmetros. Por padrão, o framework usa uma abordagem baseada em convenção para mapear automaticamente os dados da solicitação para os parâmetros do método Action, mas podemos também podem usar a vinculação explícita de parâmetros para obter mais controle sobre esse processo.

No .NET 7.0, a vinculação de parâmetros para ações de controladores de API foi alterada para inferir automaticamente a fonte de vinculação de cada parâmetro. Isso significa que não é mais necessário decorar parâmetros com atributos como [FromServices] para vinculá-los ao contêiner de injeção de dependência (DI).

O mecanismo de inferência de vinculação de parâmetros segue as seguintes regras:

Para entender como essas regras funcionam, vamos dar uma olhada em alguns exemplos:

1- Parâmetros do tipo primitivo

[Route("[controller]")]
[ApiController]
public class TesteController : ControllerBase
{
    public ActionResult Get(int id)
    {
        return Ok(id);
    }
}

Neste exemplo, o parâmetro id é do tipo primitivo int. Logo ele é vinculado a partir dos dados de solicitação.

2- Parâmetros do tipo de Entidade

[Route("[controller]")]
[ApiController]
public class TesteController : ControllerBase
{
    public ActionResult Get(Produto produto)
    {
        return Ok(produto);
    }
}

Aqui  o parâmetro produto é do tipo de entidade Produto, e, ele pode ser vinculado a partir dos dados de solicitação ou do contêiner de DI.

3- Parâmetros do tipo de serviço

[Route("[controller]")]
[ApiController]
public class TesteController : ControllerBase
{
    public ActionResult Get(ILogger logger)
    {
        return Ok(logger);
    }
}

Neste código, o parâmetro logger é do tipo de serviço ILogger. Portanto, ele é vinculado a partir do contêiner de DI visto que o serviço é configurado por padrão.

Existem algumas exceções a essas regras. Por exemplo, parâmetros com atributos personalizados que implementam IBindingInfo são sempre vinculados a partir desses atributos. Além disso, parâmetros com atributos personalizados que implementam IFromControllerMetadata são sempre vinculados a partir dos dados de solicitação.

Se você precisar alterar a fonte de vinculação de um parâmetro, você pode usar o atributo [FromService] para vinculá-lo ao contêiner de DI ou o atributo [FromBody] para vinculá-lo a partir dos dados de solicitação.

Aqui está um exemplo de como usar o atributo [FromService] para vincular um parâmetro a um serviço do contêiner de DI:

[Route("[controller]")]
[ApiController]
public class MyController : ControllerBase
{
    public ActionResult Get([FromService] ILogger logger)
    {
        return Ok(logger);
    }
}

O parâmetro logger é vinculado ao serviço logger do contêiner de DI

A seguir temos um exemplo de como usar o atributo [FromBody] para vincular um parâmetro a partir dos dados de solicitação:

[Route("[controller]")]
[ApiController]
public class TesteController : ControllerBase
{
    public ActionResult Get([FromBody] Produto produto)
    {
        return Ok(produto);
    }
}

O parâmetro produto é vinculado aos dados de solicitação.

A ASP.NET Core faz conversões internas parecidas com o Convert.ChangeType() ou TypeConverter para transformar strings da requisição em: int, bool, DateTime, enum, Guid. Objetos complexos (com propriedades internas recursivas)

Se o valor for inválido (ex: string "abc" para um int), o ModelState entra como inválido.

Como o ASP.NET Core faz isso internamente?

O pipeline de Model Binding:
- Identifica a origem dos dados: QueryString, Rota, Body, Form, etc
- Lê os dados como string
- Tenta converter para o tipo de destino do parâmetro
- Se falhar a conversão: O ModelState fica inválido

A vinculação de parâmetros simplifica a escrita do código para lidar com solicitações HTTP, e permite tratar com mais facilidade com tipos de dados complexos, ao mesmo tempo que simplificam o código e melhoram a capacidade de manutenção do código, ao mesmo tempo em que constroem a lógica de seus endpoints nas APIs.

E estamos conversados...

"E Jesus lhe disse: Vai, a tua fé te salvou. E logo viu, e seguiu a Jesus pelo caminho."
Marcos 10:52

Referências:


José Carlos Macoratti